Repository: CartoDB/cartoframes
Pull request #1175 (2019-11-07 14:48:52)

Improve credentials UX
Fixes https://github.com/CartoDB/cartoframes/issues/1028, https://github.com/CartoDB/cartoframes/issues/776, https://github.com/CartoDB/cartoframes/issues/1022

- Add Credentials.save() output message
- Check Credentials in a Table/Query Dataset
- Allow passing file path to set_default_credentials
- Add `credentials` param to all viz helper methods
- Add/Update tests
- Move enrichment tests to e2e folder




Patch:
diff --git a/cartoframes/auth/credentials.py b/cartoframes/auth/credentials.py
index 66a75325..24b4117e 100644
--- a/cartoframes/auth/credentials.py
+++ b/cartoframes/auth/credentials.py
@@ -165,7 +165,7 @@ class Credentials(object):
 
                 from cartoframes.auth import Credentials
                 credentials = Credentials(username='johnsmith', api_key='abcdefg')
-                credentials.save('path/to/credentials/file')
+                credentials.save('path/to/credentials/file.json')
         """
 
         if config_file is None:
@@ -177,6 +177,8 @@ class Credentials(object):
 
         with open(config_file, 'w') as _file:
             json.dump({'username': self._username, 'api_key': self._api_key, 'base_url': self._base_url}, _file)
+            print('User credentials for `{0}` were successfully saved to `{1}`'.format(
+                self._username or self._base_url, config_file))
 
     @classmethod
     def delete(cls, config_file=None):
diff --git a/cartoframes/auth/defaults.py b/cartoframes/auth/defaults.py
index 453d5af8..91e21bb0 100644
--- a/cartoframes/auth/defaults.py
+++ b/cartoframes/auth/defaults.py
@@ -8,7 +8,7 @@ _default_credentials = None
 
 
 def set_default_credentials(
-        first=None, second=None, credentials=None,
+        first=None, second=None, credentials=None, filepath=None,
         username=None, base_url=None, api_key=None, session=None):
     """Set default credentials for all operations that require authentication
     against a CARTO account. CARTOframes methods
@@ -30,6 +30,7 @@ def set_default_credentials(
         api_key (str, optional): CARTO API key. Depending on the application,
           this can be a project API key or the account master API key.
         username (str, optional): CARTO user name of the account.
+        filepath (str, optional): Location where credentials are stored as a JSON file.
         session (requests.Session, optional): requests session. See `requests
           documentation
           <https://2.python-requests.org/en/master/user/advanced/#session-objects>`__
@@ -65,13 +66,10 @@ def set_default_credentials(
             from cartoframes.auth import Credentials, set_default_credentials
 
             # attempts to read file from default location if it exists
-            creds = Credentials.from_file()
+            set_default_credentials()
 
             # read credentials from specified location
-            creds = Credentials.from_file('./carto-project-credentials.json')
-
-            # set default credentials from file
-            set_default_credentials(Credentials.from_file())
+            set_default_credentials('./carto-project-credentials.json')
 
 
     Example:
@@ -146,12 +144,17 @@ def set_default_credentials(
 
     _base_url = base_url if first is None else first
     _username = username if first is None else first
+    _filepath = filepath if first is None else first
     _api_key = (api_key if second is None else second) or 'default_public'
     _credentials = credentials if first is None else first
 
     if isinstance(_credentials, Credentials):
         _default_credentials = _credentials
 
+    elif isinstance(_filepath, str):
+        if _is_json_filepath(_filepath):
+            _default_credentials = Credentials.from_file(_filepath)
+
     elif isinstance(_base_url or _username, str) and isinstance(_api_key, str):
         if _base_url and _is_url(_base_url):
             _default_credentials = Credentials(base_url=_base_url, api_key=_api_key)
@@ -159,8 +162,11 @@ def set_default_credentials(
             _default_credentials = Credentials(username=_username, api_key=_api_key)
 
     else:
-        raise ValueError(
-            'Invalid inputs. Pass a Credentials object, a username and api_key pair or a base_url and api_key pair.')
+        try:
+            _default_credentials = Credentials.from_file()
+        except Exception:
+            raise Exception('There is no default credentials file. '
+                            'Run `Credentials(...).save()` to create a credentials file.')
 
     if session:
         _default_credentials.session = session
@@ -178,7 +184,7 @@ def get_default_credentials():
 
             from cartoframes.auth import set_default_credentials, get_default_credentials
 
-            set_default_credentials(Credentials.from_file())
+            set_default_credentials()
 
             current_creds = get_default_credentials()
 
@@ -194,3 +200,7 @@ def get_default_credentials():
 
 def _is_url(text):
     return re.match(r'^https?://.*$', text)
+
+
+def _is_json_filepath(text):
+    return re.match(r'^.*\.json\s*$', text, re.IGNORECASE)
diff --git a/cartoframes/data/dataset/dataset.py b/cartoframes/data/dataset/dataset.py
index d619aba8..dc97f177 100644
--- a/cartoframes/data/dataset/dataset.py
+++ b/cartoframes/data/dataset/dataset.py
@@ -463,7 +463,7 @@ class Dataset(object):
     def _init_strategy(self, data, credentials=None, schema=None):
         credentials = credentials or get_default_credentials()
         for strategy in self._registry.get_strategies():
-            if strategy.can_work_with(data):
+            if strategy.can_work_with(data, credentials):
                 return strategy.create(data, credentials, schema)
 
         raise ValueError('We can not detect the Dataset type')
diff --git a/cartoframes/data/dataset/registry/base_dataset.py b/cartoframes/data/dataset/registry/base_dataset.py
index 3ccc8b7b..80b7c670 100644
--- a/cartoframes/data/dataset/registry/base_dataset.py
+++ b/cartoframes/data/dataset/registry/base_dataset.py
@@ -37,7 +37,7 @@ class BaseDataset():
 
     @staticmethod
     @abstractmethod
-    def can_work_with():
+    def can_work_with(data, credentials):
         pass
 
     @classmethod
diff --git a/cartoframes/data/dataset/registry/dataframe_dataset.py b/cartoframes/data/dataset/registry/dataframe_dataset.py
index b2079f58..5b0bc392 100644
--- a/cartoframes/data/dataset/registry/dataframe_dataset.py
+++ b/cartoframes/data/dataset/registry/dataframe_dataset.py
@@ -21,7 +21,7 @@ class DataFrameDataset(BaseDataset):
         self._df = data
 
     @staticmethod
-    def can_work_with(data):
+    def can_work_with(data, credentials):
         return isinstance(data, pd.DataFrame) or is_geojson(data)
 
     @classmethod
diff --git a/cartoframes/data/dataset/registry/query_dataset.py b/cartoframes/data/dataset/registry/query_dataset.py
index e931ab94..ca3b80f9 100644
--- a/cartoframes/data/dataset/registry/query_dataset.py
+++ b/cartoframes/data/dataset/registry/query_dataset.py
@@ -2,7 +2,7 @@ from __future__ import absolute_import
 
 from carto.exceptions import CartoException, CartoRateLimitException
 
-from ....utils.utils import is_sql_query
+from ....utils.utils import is_sql_query, check_credentials
 from .base_dataset import BaseDataset
 
 
@@ -13,7 +13,8 @@ class QueryDataset(BaseDataset):
         self._query = data
 
     @staticmethod
-    def can_work_with(data):
+    def can_work_with(data, credentials):
+        check_credentials(credentials)
         return is_sql_query(data)
 
     @classmethod
diff --git a/cartoframes/data/dataset/registry/table_dataset.py b/cartoframes/data/dataset/registry/table_dataset.py
index 3a670cc9..b5c8768c 100644
--- a/cartoframes/data/dataset/registry/table_dataset.py
+++ b/cartoframes/data/dataset/registry/table_dataset.py
@@ -5,7 +5,7 @@ from warnings import warn
 from carto.exceptions import CartoException, CartoRateLimitException
 
 from ....utils.columns import Column, normalize_name
-from ....utils.utils import is_table_name
+from ....utils.utils import is_table_name, check_credentials
 from .base_dataset import BaseDataset
 
 
@@ -20,7 +20,8 @@ class TableDataset(BaseDataset):
             warn('Table will be named `{}`'.format(self._table_name))
 
     @staticmethod
-    def can_work_with(data):
+    def can_work_with(data, credentials):
+        check_credentials(credentials)
         return is_table_name(data)
 
     @classmethod
diff --git a/cartoframes/utils/utils.py b/cartoframes/utils/utils.py
index b85df00c..d5892c77 100644
--- a/cartoframes/utils/utils.py
+++ b/cartoframes/utils/utils.py
@@ -2,7 +2,6 @@
 
 from __future__ import absolute_import
 
-import os
 import re
 import sys
 import json
@@ -232,6 +231,8 @@ def load_geojson(input_data):
                 'properties': {},
                 'geometry': input_data
             }])
+        else:
+            data = geopandas.GeoDataFrame()
 
     else:
         raise ValueError(
@@ -287,7 +288,7 @@ def is_geojson_file(data):
 
 
 def is_geojson_file_path(data):
-    return is_geojson_file(data) and os.path.exists(data)
+    return is_geojson_file(data)
 
 
 def is_geojson(data):
@@ -300,6 +301,13 @@ def is_table_name(data):
     return isinstance(data, str) and normalize_name(data) == data
 
 
+def check_credentials(credentials):
+    if credentials is None:
+        raise AttributeError('Credentials attribute is required. '
+                             'Please pass a `Credentials` instance '
+                             'or use the `set_default_credentials` function.')
+
+
 def get_center(center):
     if 'lng' not in center or 'lat' not in center:
         return None
diff --git a/cartoframes/viz/helpers/animation_layer.py b/cartoframes/viz/helpers/animation_layer.py
index 593bd328..b794a7dd 100644
--- a/cartoframes/viz/helpers/animation_layer.py
+++ b/cartoframes/viz/helpers/animation_layer.py
@@ -8,7 +8,7 @@ from ..layer import Layer
 def animation_layer(
         source, value, title='', duration=None, fade=None, size=None,
         color=None, opacity=None, stroke_color=None, stroke_width=None,
-        widget_type='time-series', description=''):
+        widget_type='time-series', description='', credentials=None):
     """Helper function for quickly creating an animated map.
 
     Args:
@@ -29,6 +29,11 @@ def animation_layer(
           The default is "time-series".
         description (str, optional): Description text placed under the widget title.
         fade (string, optional): Animation fade with the format: "(fade in, fade out)". Default is (1, 1).
+        credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
+          A Credentials instance. This is only used for the simplified Source API.
+          When a :py:class:`Source <cartoframes.viz.Source>` is pased as source,
+          these credentials is simply ignored. If not provided the credentials will be
+          automatically obtained from the default credentials.
 
     Returns:
         cartoframes.viz.Layer: Layer styled by `value`. Includes Widget `value`.
@@ -69,5 +74,6 @@ def animation_layer(
             'value': value,
             'title': title,
             'description': description
-        }]
+        }],
+        credentials=credentials
     )
diff --git a/cartoframes/viz/helpers/cluster_size_layer.py b/cartoframes/viz/helpers/cluster_size_layer.py
index 02d271c0..152b871e 100644
--- a/cartoframes/viz/helpers/cluster_size_layer.py
+++ b/cartoframes/viz/helpers/cluster_size_layer.py
@@ -11,7 +11,7 @@ def cluster_size_layer(
         source, value=None, operation='count', resolution=32,
         title='', color=None, opacity=None,
         stroke_width=None, stroke_color=None, description='',
-        footer='', legend=True, popup=True, widget=False, animate=None):
+        footer='', legend=True, popup=True, widget=False, animate=None, credentials=None):
     """Helper function for quickly creating a cluster map with
     continuously sized points.
 
@@ -39,6 +39,11 @@ def cluster_size_layer(
         widget (bool, optional): Display a widget for mapped data.
           Set to "False" by default.
         animate (str, optional): Animate features by date/time or other numeric field.
+        credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
+          A Credentials instance. This is only used for the simplified Source API.
+          When a :py:class:`Source <cartoframes.viz.Source>` is pased as source,
+          these credentials is simply ignored. If not provided the credentials will be
+          automatically obtained from the default credentials.
 
     Returns:
         cartoframes.viz.Layer: Layer styled by `value`.
@@ -92,7 +97,8 @@ def cluster_size_layer(
                 'value': value,
                 'title': 'Distribution'
             }
-        ]
+        ],
+        credentials=credentials
     )
 
 
diff --git a/cartoframes/viz/helpers/color_bins_layer.py b/cartoframes/viz/helpers/color_bins_layer.py
index 3310b295..7138f235 100644
--- a/cartoframes/viz/helpers/color_bins_layer.py
+++ b/cartoframes/viz/helpers/color_bins_layer.py
@@ -9,7 +9,7 @@ def color_bins_layer(
         source, value, title='', method='quantiles', bins=5,
         breaks=None, palette=None, size=None, opacity=None,
         stroke_color=None, stroke_width=None, description='',
-        footer='', legend=True, popup=True, widget=False, animate=None):
+        footer='', legend=True, popup=True, widget=False, animate=None, credentials=None):
     """Helper function for quickly creating a classed color map.
 
     Args:
@@ -38,6 +38,11 @@ def color_bins_layer(
         widget (bool, optional): Display a widget for mapped data: "True" or "False".
           Set to "False" by default.
         animate (str, optional): Animate features by date/time or other numeric field.
+        credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
+          A Credentials instance. This is only used for the simplified Source API.
+          When a :py:class:`Source <cartoframes.viz.Source>` is pased as source,
+          these credentials is simply ignored. If not provided the credentials will be
+          automatically obtained from the default credentials.
 
     Returns:
         cartoframes.viz.Layer: Layer styled by `value`.
@@ -125,5 +130,6 @@ def color_bins_layer(
                 'value': value,
                 'title': 'Distribution'
             }
-        ]
+        ],
+        credentials=credentials
     )
diff --git a/cartoframes/viz/helpers/color_category_layer.py b/cartoframes/viz/helpers/color_category_layer.py
index fc8aef98..f8f06bdc 100644
--- a/cartoframes/viz/helpers/color_category_layer.py
+++ b/cartoframes/viz/helpers/color_category_layer.py
@@ -9,7 +9,7 @@ def color_category_layer(
         source, value, title='', top=11, cat=None, palette=None,
         size=None, opacity=None, stroke_color=None, stroke_width=None,
         description='', footer='', legend=True, popup=True,
-        widget=False, animate=None):
+        widget=False, animate=None, credentials=None):
     """Helper function for quickly creating a category color map.
 
     Args:
@@ -37,6 +37,11 @@ def color_category_layer(
         widget (bool, optional): Display a widget for mapped data.
           Set to "False" by default.
         animate (str, optional): Animate features by date/time or other numeric field.
+        credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
+          A Credentials instance. This is only used for the simplified Source API.
+          When a :py:class:`Source <cartoframes.viz.Source>` is pased as source,
+          these credentials is simply ignored. If not provided the credentials will be
+          automatically obtained from the default credentials.
 
     Returns:
         cartoframes.viz.Layer: Layer styled by `value`.
@@ -107,5 +112,6 @@ def color_category_layer(
                 'value': value,
                 'title': 'Categories'
             }
-        ]
+        ],
+        credentials=credentials
     )
diff --git a/cartoframes/viz/helpers/color_continuous_layer.py b/cartoframes/viz/helpers/color_continuous_layer.py
index 6e1463eb..ce3be75f 100644
--- a/cartoframes/viz/helpers/color_continuous_layer.py
+++ b/cartoframes/viz/helpers/color_continuous_layer.py
@@ -9,7 +9,7 @@ def color_continuous_layer(
         source, value, title='', range_min=None, range_max=None,
         palette=None, size=None, opacity=None, stroke_color=None,
         stroke_width=None, description='', footer='', legend=True, popup=True,
-        widget=False, animate=None):
+        widget=False, animate=None, credentials=None):
     """Helper function for quickly creating a continuous color map.
 
     Args:
@@ -38,6 +38,12 @@ def color_continuous_layer(
         widget (bool, optional): Display a widget for mapped data.
           Set to "False" by default.
         animate (str, optional): Animate features by date/time or other numeric field.
+        credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
+          A Credentials instance. This is only used for the simplified Source API.
+          When a :py:class:`Source <cartoframes.viz.Source>` is pased as source,
+          these credentials is simply ignored. If not provided the credentials will be
+          automatically obtained from the default credentials.
+
 
     Returns:
         cartoframes.viz.Layer: Layer styled by `value`.
@@ -113,5 +119,6 @@ def color_continuous_layer(
                 'value': value,
                 'title': 'Distribution'
             }
-        ]
+        ],
+        credentials=credentials
     )
diff --git a/cartoframes/viz/helpers/size_bins_layer.py b/cartoframes/viz/helpers/size_bins_layer.py
index 1f2d150a..5f5eddcf 100644
--- a/cartoframes/viz/helpers/size_bins_layer.py
+++ b/cartoframes/viz/helpers/size_bins_layer.py
@@ -8,7 +8,7 @@ def size_bins_layer(
         source, value, title='', method='quantiles', bins=5,
         breaks=None, size=None, color=None, opacity=None,
         stroke_width=None, stroke_color=None, description='',
-        footer='', legend=True, popup=True, widget=False, animate=None):
+        footer='', legend=True, popup=True, widget=False, animate=None, credentials=None):
     """Helper function for quickly creating a size symbol map with
     classification method/buckets.
 
@@ -40,6 +40,11 @@ def size_bins_layer(
         widget (bool, optional): Display a widget for mapped data.
           Set to "False" by default.
         animate (str, optional): Animate features by date/time or other numeric field.
+        credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
+          A Credentials instance. This is only used for the simplified Source API.
+          When a :py:class:`Source <cartoframes.viz.Source>` is pased as source,
+          these credentials is simply ignored. If not provided the credentials will be
+          automatically obtained from the default credentials.
 
     Returns:
         cartoframes.viz.Layer: Layer styled by `value`.
@@ -110,5 +115,6 @@ def size_bins_layer(
                 'value': value,
                 'title': 'Distribution'
             }
-        ]
+        ],
+        credentials=credentials
     )
diff --git a/cartoframes/viz/helpers/size_category_layer.py b/cartoframes/viz/helpers/size_category_layer.py
index 57933e49..4fe00f33 100644
--- a/cartoframes/viz/helpers/size_category_layer.py
+++ b/cartoframes/viz/helpers/size_category_layer.py
@@ -8,7 +8,7 @@ def size_category_layer(
         source, value, title='', top=5, cat=None,
         size=None, color=None, opacity=None, stroke_width=None,
         stroke_color=None, description='', footer='',
-        legend=True, popup=True, widget=False, animate=None):
+        legend=True, popup=True, widget=False, animate=None, credentials=None):
     """Helper function for quickly creating a size category layer.
 
     Args:
@@ -39,6 +39,11 @@ def size_category_layer(
         widget (bool, optional): Display a widget for mapped data.
           Set to "False" by default.
         animate (str, optional): Animate features by date/time or other numeric field.
+        credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
+          A Credentials instance. This is only used for the simplified Source API.
+          When a :py:class:`Source <cartoframes.viz.Source>` is pased as source,
+          these credentials is simply ignored. If not provided the credentials will be
+          automatically obtained from the default credentials.
 
     Returns:
         cartoframes.viz.Layer: Layer styled by `value`.
@@ -97,5 +102,6 @@ def size_category_layer(
                 'value': value,
                 'title': 'Categories'
             }
-        ]
+        ],
+        credentials=credentials
     )
diff --git a/cartoframes/viz/helpers/size_continuous_layer.py b/cartoframes/viz/helpers/size_continuous_layer.py
index 188dd898..d54a6263 100644
--- a/cartoframes/viz/helpers/size_continuous_layer.py
+++ b/cartoframes/viz/helpers/size_continuous_layer.py
@@ -7,7 +7,7 @@ from ..layer import Layer
 def size_continuous_layer(
         source, value, title='', range_min=None, range_max=None, size=None, color=None,
         opacity=None, stroke_width=None, stroke_color=None, description='', footer='',
-        legend=True, popup=True, widget=False, animate=None):
+        legend=True, popup=True, widget=False, animate=None, credentials=None):
     """Helper function for quickly creating a size symbol map with
     continuous size scaled by `value`.
 
@@ -39,6 +39,11 @@ def size_continuous_layer(
         widget (bool, optional): Display a widget for mapped data.
           Set to "False" by default.
         animate (str, optional): Animate features by date/time or other numeric field.
+        credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
+          A Credentials instance. This is only used for the simplified Source API.
+          When a :py:class:`Source <cartoframes.viz.Source>` is pased as source,
+          these credentials is simply ignored. If not provided the credentials will be
+          automatically obtained from the default credentials.
 
     Returns:
         cartoframes.viz.Layer: Layer styled by `value`.
@@ -107,5 +112,6 @@ def size_continuous_layer(
                 'value': value,
                 'title': 'Distribution'
             }
-        ]
+        ],
+        credentials=credentials
     )
diff --git a/cartoframes/viz/layer.py b/cartoframes/viz/layer.py
index 2b9c59ce..e35afe1d 100644
--- a/cartoframes/viz/layer.py
+++ b/cartoframes/viz/layer.py
@@ -37,10 +37,10 @@ class Layer(object):
           "title", "description" and "footer". See :py:class:`Legend
           <cartoframes.viz.Legend>` for more information.
         widgets (dict, list, or :py:class:`WidgetList <cartoframes.viz.WidgetList>`, optional):
-           Widget or list of widgets for a layer. It contains the information to display
-           different widget types on the top right of the map. See
-           :py:class:`WidgetList` for more information.
-        credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`):
+          Widget or list of widgets for a layer. It contains the information to display
+          different widget types on the top right of the map. See
+          :py:class:`WidgetList` for more information.
+        credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
           A Credentials instance. This is only used for the simplified Source API.
           When a :py:class:`Source <cartoframes.viz.Source>` is pased as source,
           these credentials is simply ignored. If not provided the credentials will be
diff --git a/setup.py b/setup.py
index f8aa329c..9967405e 100644
--- a/setup.py
+++ b/setup.py
@@ -31,6 +31,7 @@ REQUIRES = [
     'carto>=1.8.1,<2.0',
     'jinja2>=2.10.1,<3.0',
     'geopandas>=0.6.0,<1.0',
+    'pyproj==2.2.2',
     'tqdm>=4.32.1,<5.0',
     'unidecode>=1.1.0,<2.0',
     'pyarrow>=0.14.1,<1.0',


Test patch:
diff --git a/tests/e2e/data/dataset/test_dataset.py b/tests/e2e/data/dataset/test_dataset.py
index a9b123e7..150a167c 100644
--- a/tests/e2e/data/dataset/test_dataset.py
+++ b/tests/e2e/data/dataset/test_dataset.py
@@ -611,11 +611,6 @@ class TestDatasetUnit(unittest.TestCase, _UserUrlLoader):
     def test_creation_from_valid_localgeojson(self):
         self.assertIsDataFrameDatasetInstance(self.test_geojson)
 
-    def test_creation_from_invalid_localgeojson(self):
-        geojson = object
-        with self.assertRaises(ValueError, msg='We can not detect the Dataset type'):
-            self.assertIsDataFrameDatasetInstance(geojson)
-
     def test_creation_from_valid_geojson_file_path(self):
         paths = [os.path.abspath('tests/e2e/data/dataset/fixtures/valid.geojson'),
                  os.path.abspath('tests/e2e/data/dataset/fixtures/validgeo.json')]
@@ -677,6 +672,22 @@ class TestDatasetUnit(unittest.TestCase, _UserUrlLoader):
         self.assertIsNone(dataset.table_name)
         self.assertIsNone(dataset.credentials)
 
+    def test_dataset_from_table_without_credentials(self):
+        table_name = 'fake_table'
+        error_msg = ('Credentials attribute is required. '
+                     'Please pass a `Credentials` instance '
+                     'or use the `set_default_credentials` function.')
+        with self.assertRaises(AttributeError, msg=error_msg):
+            Dataset(table_name)
+
+    def test_dataset_from_query_without_credentials(self):
+        query = 'SELECT * FROM fake_table'
+        error_msg = ('Credentials attribute is required. '
+                     'Please pass a `Credentials` instance '
+                     'or use the `set_default_credentials` function.')
+        with self.assertRaises(AttributeError, msg=error_msg):
+            Dataset(query)
+
     def test_dataset_get_table_names_from_table(self):
         table_name = 'fake_table'
         dataset = DatasetMock(table_name, credentials=self.credentials)
diff --git a/tests/unit/data/observatory/enrichment/test_points_enrichment.py b/tests/e2e/data/observatory/enrichment/test_points_enrichment.py
similarity index 100%
rename from tests/unit/data/observatory/enrichment/test_points_enrichment.py
rename to tests/e2e/data/observatory/enrichment/test_points_enrichment.py
diff --git a/tests/unit/data/observatory/enrichment/test_polygon_enrichment.py b/tests/e2e/data/observatory/enrichment/test_polygon_enrichment.py
similarity index 100%
rename from tests/unit/data/observatory/enrichment/test_polygon_enrichment.py
rename to tests/e2e/data/observatory/enrichment/test_polygon_enrichment.py
diff --git a/tests/unit/data/observatory/enrichment/test_service.py b/tests/e2e/data/observatory/enrichment/test_service.py
similarity index 100%
rename from tests/unit/data/observatory/enrichment/test_service.py
rename to tests/e2e/data/observatory/enrichment/test_service.py
diff --git a/tests/unit/auth/test_auth_api_client.py b/tests/unit/auth/test_auth_api_client.py
index 6ff8e4d5..7efebdd0 100644
--- a/tests/unit/auth/test_auth_api_client.py
+++ b/tests/unit/auth/test_auth_api_client.py
@@ -1,5 +1,7 @@
 from cartoframes.data import Dataset
 from cartoframes.data.clients.auth_api_client import AuthAPIClient
+from cartoframes.auth import Credentials
+from cartoframes.lib.context.api_context import APIContext
 
 
 try:
@@ -35,11 +37,12 @@ class TestSQLClient(object):
         assert isinstance(auth_api_client, AuthAPIClient)
         assert isinstance(auth_api_client._api_key_manager, APIKeyManagerMock)
 
+    @patch.object(APIContext, 'get_schema')
     @patch('cartoframes.data.clients.auth_api_client._get_api_key_manager')
-    def test_create_api_key(self, get_api_key_manager_mock):
+    def test_create_api_key(self, get_api_key_manager_mock, get_schema_mock):
         get_api_key_manager_mock.return_value = APIKeyManagerMock()
 
-        dataset = Dataset('fake_table')
+        dataset = Dataset('fake_table', credentials=Credentials('fakeuser'))
         api_key_name = 'fake_name'
 
         auth_api_client = AuthAPIClient()
@@ -47,11 +50,12 @@ class TestSQLClient(object):
 
         assert token == TOKEN_MOCK
 
+    @patch.object(APIContext, 'get_schema')
     @patch('cartoframes.data.clients.auth_api_client._get_api_key_manager')
-    def test_create_api_key_several_datasets(self, get_api_key_manager_mock):
+    def test_create_api_key_several_datasets(self, get_api_key_manager_mock, get_schema_mock):
         get_api_key_manager_mock.return_value = APIKeyManagerMock()
 
-        dataset = Dataset('fake_table')
+        dataset = Dataset('fake_table', credentials=Credentials('fakeuser'))
         api_key_name = 'fake_name'
 
         auth_api_client = AuthAPIClient()
diff --git a/tests/unit/auth/test_credentials.py b/tests/unit/auth/test_credentials.py
index 7d2f06f9..e03d0473 100644
--- a/tests/unit/auth/test_credentials.py
+++ b/tests/unit/auth/test_credentials.py
@@ -8,8 +8,10 @@ from cartoframes.auth.credentials import _DEFAULT_PATH, _USER_CONFIG_DIR
 # FIXME python 2.7 compatibility
 try:
     FileNotFoundError
+    from io import StringIO
 except NameError:
     FileNotFoundError = IOError
+    from io import BytesIO as StringIO
 
 
 class TestCredentials(object):
@@ -169,23 +171,32 @@ class TestCredentialsFromFile(object):
         self.username = 'fake_user'
 
     def teardown_method(self, method):
+        if os.path.exists(_DEFAULT_PATH):
+            os.remove(_DEFAULT_PATH)
+
         if os.path.exists(_USER_CONFIG_DIR):
             os.rmdir(_USER_CONFIG_DIR)
 
-    def test_credentials_without_file(self):
+    def test_credentials_without_file(self, mocker):
+        mocker_stdout = mocker.patch('sys.stdout', new_callable=StringIO)
+
         credentials1 = Credentials(self.username, self.api_key)
         credentials1.save()
 
         credentials2 = Credentials.from_file()
 
         assert credentials1 == credentials2
+        assert mocker_stdout.getvalue() == 'User credentials for `{0}` were successfully saved to `{1}`\n'.format(
+            self.username, _DEFAULT_PATH)
 
         credentials1.delete()
 
         with pytest.raises(FileNotFoundError):
             Credentials.from_file()
 
-    def test_credentials_with_file(self):
+    def test_credentials_with_file(self, mocker):
+        mocker_stdout = mocker.patch('sys.stdout', new_callable=StringIO)
+
         file = '/tmp/credentials.json'
         credentials1 = Credentials(self.username, self.api_key)
         credentials1.save(file)
@@ -193,6 +204,8 @@ class TestCredentialsFromFile(object):
         credentials2 = Credentials.from_file(file)
 
         assert credentials1 == credentials2
+        assert mocker_stdout.getvalue() == 'User credentials for `{0}` were successfully saved to `{1}`\n'.format(
+            self.username, file)
 
         credentials1.delete(file)
 
diff --git a/tests/unit/viz/helpers/test_cluster_size_layer.py b/tests/unit/viz/helpers/test_cluster_size_layer.py
index e6898a6d..bb11051e 100644
--- a/tests/unit/viz/helpers/test_cluster_size_layer.py
+++ b/tests/unit/viz/helpers/test_cluster_size_layer.py
@@ -1,12 +1,18 @@
 import pytest
+
 from carto.exceptions import CartoException
 
 from cartoframes.viz import helpers
+from cartoframes.auth import Credentials
 
 from . import setup_mocks
+from ..utils import simple_dataframe
 
 
 class TestClusterSizeLayerHelper(object):
+    def setup_method(self):
+        self.source = simple_dataframe()
+
     def test_helpers(self):
         "should be defined"
         assert helpers.cluster_size_layer is not None
@@ -16,8 +22,9 @@ class TestClusterSizeLayerHelper(object):
         setup_mocks(mocker)
 
         layer = helpers.cluster_size_layer(
-            source='sf_neighborhoods',
-            value='name'
+            source='SELECT * FROM faketable',
+            value='name',
+            credentials=Credentials('fakeuser')
         )
 
         assert layer.style is not None
@@ -46,7 +53,7 @@ class TestClusterSizeLayerHelper(object):
         msg = '"invalid" is not a valid operation. Valid operations are count, avg, min, max, sum'
         with pytest.raises(CartoException) as e:
             helpers.cluster_size_layer(
-                source='sf_neighborhoods',
+                source=self.source,
                 value='name',
                 operation='invalid'
             )
diff --git a/tests/unit/viz/helpers/test_color_bins_layer.py b/tests/unit/viz/helpers/test_color_bins_layer.py
index 44efb463..48b51683 100644
--- a/tests/unit/viz/helpers/test_color_bins_layer.py
+++ b/tests/unit/viz/helpers/test_color_bins_layer.py
@@ -1,11 +1,16 @@
 import pytest
 
 from cartoframes.viz import helpers
+from cartoframes.auth import Credentials
 
 from . import setup_mocks
+from ..utils import simple_dataframe
 
 
 class TestColorBinsLayerHelper(object):
+    def setup_method(self):
+        self.source = simple_dataframe()
+
     def test_helpers(self):
         "should be defined"
         assert helpers.color_bins_layer is not None
@@ -14,8 +19,9 @@ class TestColorBinsLayerHelper(object):
         "should create a layer with the proper attributes"
         setup_mocks(mocker)
         layer = helpers.color_bins_layer(
-            source='sf_neighborhoods',
-            value='name'
+            source='SELECT * FROM faketable',
+            value='name',
+            credentials=Credentials('fakeuser')
         )
 
         assert layer.style is not None
@@ -40,7 +46,7 @@ class TestColorBinsLayerHelper(object):
         "should create a point type layer"
         setup_mocks(mocker)
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             bins=3,
@@ -53,7 +59,7 @@ class TestColorBinsLayerHelper(object):
         "should create a line type layer"
         setup_mocks(mocker, 'line')
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             bins=3,
@@ -66,7 +72,7 @@ class TestColorBinsLayerHelper(object):
         "should create a polygon type layer"
         setup_mocks(mocker, 'polygon')
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             bins=3,
@@ -79,7 +85,7 @@ class TestColorBinsLayerHelper(object):
         "should apply the classification method"
         setup_mocks(mocker)
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             method='quantiles'
         )
@@ -89,7 +95,7 @@ class TestColorBinsLayerHelper(object):
         assert layer.style._style['polygon']['color'] == 'opacity(ramp(globalQuantiles($name, 5), purpor), 0.9)'
 
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             method='equal'
         )
@@ -99,7 +105,7 @@ class TestColorBinsLayerHelper(object):
         assert layer.style._style['polygon']['color'] == 'opacity(ramp(globalEqIntervals($name, 5), purpor), 0.9)'
 
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             method='stdev'
         )
@@ -111,7 +117,7 @@ class TestColorBinsLayerHelper(object):
         msg = 'Available methods are: "quantiles", "equal", "stdev".'
         with pytest.raises(ValueError) as e:
             helpers.color_bins_layer(
-                'sf_neighborhoods',
+                self.source,
                 'name',
                 method='wrong_method'
             )
@@ -121,7 +127,7 @@ class TestColorBinsLayerHelper(object):
         "should apply buckets if breaks are passed"
         setup_mocks(mocker)
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             breaks=[0, 1, 2]
         )
@@ -134,7 +140,7 @@ class TestColorBinsLayerHelper(object):
         "should show/hide the legend"
         setup_mocks(mocker)
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=False
         )
@@ -143,7 +149,7 @@ class TestColorBinsLayerHelper(object):
         assert layer.legend._title == ''
 
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=True
         )
@@ -159,7 +165,7 @@ class TestColorBinsLayerHelper(object):
         "should show/hide the popup"
         setup_mocks(mocker)
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=False
         )
@@ -167,7 +173,7 @@ class TestColorBinsLayerHelper(object):
         assert layer.popup._hover == []
 
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=True
         )
@@ -181,7 +187,7 @@ class TestColorBinsLayerHelper(object):
         "should show/hide the widget"
         setup_mocks(mocker)
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=False
         )
@@ -189,7 +195,7 @@ class TestColorBinsLayerHelper(object):
         assert layer.widgets._widgets == []
 
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=True
         )
@@ -201,7 +207,7 @@ class TestColorBinsLayerHelper(object):
         "should animate a property and disable the popups"
         setup_mocks(mocker)
         layer = helpers.color_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             animate='time'
         )
diff --git a/tests/unit/viz/helpers/test_color_category_layer.py b/tests/unit/viz/helpers/test_color_category_layer.py
index 9bba66ab..719a6316 100644
--- a/tests/unit/viz/helpers/test_color_category_layer.py
+++ b/tests/unit/viz/helpers/test_color_category_layer.py
@@ -1,9 +1,14 @@
 from cartoframes.viz import helpers
+from cartoframes.auth import Credentials
 
 from . import setup_mocks
+from ..utils import simple_dataframe
 
 
-class TestColorCategoryLayerHelper():
+class TestColorCategoryLayerHelper(object):
+    def setup_method(self):
+        self.source = simple_dataframe()
+
     def test_helpers(self):
         "should be defined"
         assert helpers.color_category_layer is not None
@@ -12,9 +17,10 @@ class TestColorCategoryLayerHelper():
         "should create a layer with the proper attributes"
         setup_mocks(mocker)
         layer = helpers.color_category_layer(
-            source='sf_neighborhoods',
+            source='SELECT * FROM faketable',
             value='name',
-            title='Neighborhoods'
+            title='Neighborhoods',
+            credentials=Credentials('fakeuser')
         )
 
         assert layer.style is not None
@@ -40,7 +46,7 @@ class TestColorCategoryLayerHelper():
         "should create a point type layer"
         setup_mocks(mocker)
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             top=5,
@@ -50,7 +56,7 @@ class TestColorCategoryLayerHelper():
         assert layer.style._style['point']['color'] == 'opacity(ramp(top($name, 5), prism),1)'
 
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             cat=['A', 'B'],
@@ -63,7 +69,7 @@ class TestColorCategoryLayerHelper():
         "should create a line type layer"
         setup_mocks(mocker, 'line')
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             top=5,
@@ -73,7 +79,7 @@ class TestColorCategoryLayerHelper():
         assert layer.style._style['line']['color'] == 'opacity(ramp(top($name, 5), prism),1)'
 
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             cat=['A', 'B'],
@@ -86,7 +92,7 @@ class TestColorCategoryLayerHelper():
         "should create a polygon type layer"
         setup_mocks(mocker, 'polygon')
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             top=5,
@@ -96,7 +102,7 @@ class TestColorCategoryLayerHelper():
         assert layer.style._style['polygon']['color'] == 'opacity(ramp(top($name, 5), prism), 0.9)'
 
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             cat=['A', 'B'],
@@ -109,7 +115,7 @@ class TestColorCategoryLayerHelper():
         "should show/hide the legend"
         setup_mocks(mocker)
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=False
         )
@@ -118,7 +124,7 @@ class TestColorCategoryLayerHelper():
         assert layer.legend._title == ''
 
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=True
         )
@@ -134,7 +140,7 @@ class TestColorCategoryLayerHelper():
         "should show/hide the popup"
         setup_mocks(mocker)
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=False
         )
@@ -142,7 +148,7 @@ class TestColorCategoryLayerHelper():
         assert layer.popup._hover == []
 
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=True
         )
@@ -156,7 +162,7 @@ class TestColorCategoryLayerHelper():
         "should show/hide the widget"
         setup_mocks(mocker)
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=False
         )
@@ -164,7 +170,7 @@ class TestColorCategoryLayerHelper():
         assert layer.widgets._widgets == []
 
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=True
         )
@@ -176,7 +182,7 @@ class TestColorCategoryLayerHelper():
         "should animate a property and disable the popups"
         setup_mocks(mocker)
         layer = helpers.color_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             animate='time'
         )
diff --git a/tests/unit/viz/helpers/test_color_continuous_layer.py b/tests/unit/viz/helpers/test_color_continuous_layer.py
index 02aad89f..1106de6f 100644
--- a/tests/unit/viz/helpers/test_color_continuous_layer.py
+++ b/tests/unit/viz/helpers/test_color_continuous_layer.py
@@ -1,9 +1,14 @@
 from cartoframes.viz import helpers
+from cartoframes.auth import Credentials
 
 from . import setup_mocks
+from ..utils import simple_dataframe
 
 
 class TestColorContinuousLayerHelper(object):
+    def setup_method(self):
+        self.source = simple_dataframe()
+
     def test_helpers(self):
         "should be defined"
         assert helpers.color_continuous_layer is not None
@@ -12,8 +17,9 @@ class TestColorContinuousLayerHelper(object):
         "should create a layer with the proper attributes"
         setup_mocks(mocker)
         layer = helpers.color_continuous_layer(
-            source='sf_neighborhoods',
-            value='name'
+            source='SELECT * FROM faketable',
+            value='name',
+            credentials=Credentials('fakeuser')
         )
 
         assert layer.style is not None
@@ -41,7 +47,7 @@ class TestColorContinuousLayerHelper(object):
         "should create a point type layer"
         setup_mocks(mocker)
         layer = helpers.color_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             palette='prism'
@@ -54,7 +60,7 @@ class TestColorContinuousLayerHelper(object):
         "should create a line type layer"
         setup_mocks(mocker, 'line')
         layer = helpers.color_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             palette='[blue,#F00]'
@@ -67,7 +73,7 @@ class TestColorContinuousLayerHelper(object):
         "should create a polygon type layer"
         setup_mocks(mocker, 'polygon')
         layer = helpers.color_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             palette=['blue', '#F00']
@@ -80,7 +86,7 @@ class TestColorContinuousLayerHelper(object):
         "should show/hide the legend"
         setup_mocks(mocker)
         layer = helpers.color_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=False
         )
@@ -89,7 +95,7 @@ class TestColorContinuousLayerHelper(object):
         assert layer.legend._title == ''
 
         layer = helpers.color_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=True
         )
@@ -105,7 +111,7 @@ class TestColorContinuousLayerHelper(object):
         "should show/hide the popup"
         setup_mocks(mocker)
         layer = helpers.color_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=False
         )
@@ -113,7 +119,7 @@ class TestColorContinuousLayerHelper(object):
         assert layer.popup._hover == []
 
         layer = helpers.color_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=True
         )
@@ -127,7 +133,7 @@ class TestColorContinuousLayerHelper(object):
         "should show/hide the widget"
         setup_mocks(mocker)
         layer = helpers.color_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=False
         )
@@ -135,7 +141,7 @@ class TestColorContinuousLayerHelper(object):
         assert layer.widgets._widgets == []
 
         layer = helpers.color_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=True
         )
@@ -147,7 +153,7 @@ class TestColorContinuousLayerHelper(object):
         "should animate a property and disable the popups"
         setup_mocks(mocker)
         layer = helpers.color_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             animate='time'
         )
diff --git a/tests/unit/viz/helpers/test_size_bins_layer.py b/tests/unit/viz/helpers/test_size_bins_layer.py
index e17986bb..3d22f18d 100644
--- a/tests/unit/viz/helpers/test_size_bins_layer.py
+++ b/tests/unit/viz/helpers/test_size_bins_layer.py
@@ -1,11 +1,16 @@
 import pytest
 
 from cartoframes.viz import helpers
+from cartoframes.auth import Credentials
 
 from . import setup_mocks
+from ..utils import simple_dataframe
 
 
 class TestSizeBinsLayerHelper(object):
+    def setup_method(self):
+        self.source = simple_dataframe()
+
     def test_helpers(self):
         "should be defined"
         assert helpers.size_bins_layer is not None
@@ -14,8 +19,9 @@ class TestSizeBinsLayerHelper(object):
         "should create a layer with the proper attributes"
         setup_mocks(mocker)
         layer = helpers.size_bins_layer(
-            source='sf_neighborhoods',
-            value='name'
+            source='SELECT * FROM faketable',
+            value='name',
+            credentials=Credentials('fakeuser')
         )
 
         assert layer.style is not None
@@ -41,7 +47,7 @@ class TestSizeBinsLayerHelper(object):
         "should create a point type layer"
         setup_mocks(mocker)
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             bins=3,
@@ -56,7 +62,7 @@ class TestSizeBinsLayerHelper(object):
         "should create a line type layer"
         setup_mocks(mocker, 'line')
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             bins=3,
@@ -71,7 +77,7 @@ class TestSizeBinsLayerHelper(object):
         "should apply the classification method"
         setup_mocks(mocker)
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             method='quantiles'
         )
@@ -80,7 +86,7 @@ class TestSizeBinsLayerHelper(object):
         assert layer.style._style['line']['width'] == 'ramp(globalQuantiles($name, 5), [1, 10])'
 
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             method='equal'
         )
@@ -89,7 +95,7 @@ class TestSizeBinsLayerHelper(object):
         assert layer.style._style['line']['width'] == 'ramp(globalEqIntervals($name, 5), [1, 10])'
 
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             method='stdev'
         )
@@ -100,7 +106,7 @@ class TestSizeBinsLayerHelper(object):
         msg = 'Available methods are: "quantiles", "equal", "stdev".'
         with pytest.raises(ValueError) as e:
             helpers.size_bins_layer(
-                'sf_neighborhoods',
+                self.source,
                 'name',
                 method='wrong'
             )
@@ -110,7 +116,7 @@ class TestSizeBinsLayerHelper(object):
         "should apply buckets if breaks are passed"
         setup_mocks(mocker)
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             breaks=[0, 1, 2]
         )
@@ -122,7 +128,7 @@ class TestSizeBinsLayerHelper(object):
         "should show/hide the legend"
         setup_mocks(mocker)
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=False
         )
@@ -131,7 +137,7 @@ class TestSizeBinsLayerHelper(object):
         assert layer.legend._title == ''
 
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=True
         )
@@ -147,7 +153,7 @@ class TestSizeBinsLayerHelper(object):
         "should show/hide the popup"
         setup_mocks(mocker)
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=False
         )
@@ -155,7 +161,7 @@ class TestSizeBinsLayerHelper(object):
         assert layer.popup._hover == []
 
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=True
         )
@@ -169,7 +175,7 @@ class TestSizeBinsLayerHelper(object):
         "should show/hide the widget"
         setup_mocks(mocker)
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=False
         )
@@ -177,7 +183,7 @@ class TestSizeBinsLayerHelper(object):
         assert layer.widgets._widgets == []
 
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=True
         )
@@ -189,7 +195,7 @@ class TestSizeBinsLayerHelper(object):
         "should animate a property and disable the popups"
         setup_mocks(mocker)
         layer = helpers.size_bins_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             animate='time'
         )
diff --git a/tests/unit/viz/helpers/test_size_category_layer.py b/tests/unit/viz/helpers/test_size_category_layer.py
index ad0ae71d..2af757c6 100644
--- a/tests/unit/viz/helpers/test_size_category_layer.py
+++ b/tests/unit/viz/helpers/test_size_category_layer.py
@@ -1,9 +1,14 @@
 from cartoframes.viz import helpers
+from cartoframes.auth import Credentials
 
 from . import setup_mocks
+from ..utils import simple_dataframe
 
 
 class TestSizeCategoryLayerHelper(object):
+    def setup_method(self):
+        self.source = simple_dataframe()
+
     def test_helpers(self):
         "should be defined"
         assert helpers.size_category_layer is not None
@@ -12,9 +17,10 @@ class TestSizeCategoryLayerHelper(object):
         "should create a layer with the proper attributes"
         setup_mocks(mocker)
         layer = helpers.size_category_layer(
-            source='sf_neighborhoods',
+            source='SELECT * FROM faketable',
             value='name',
-            title='Neighborhoods'
+            title='Neighborhoods',
+            credentials=Credentials('fakeuser')
         )
 
         assert layer.style is not None
@@ -40,7 +46,7 @@ class TestSizeCategoryLayerHelper(object):
         "should create a point type layer"
         setup_mocks(mocker)
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             top=5,
@@ -52,7 +58,7 @@ class TestSizeCategoryLayerHelper(object):
         assert layer.style._style['point']['color'] == 'opacity(blue, 0.8)'
 
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             cat=['A', 'B'],
@@ -67,7 +73,7 @@ class TestSizeCategoryLayerHelper(object):
         "should create a line type layer"
         setup_mocks(mocker, 'line')
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             top=5,
@@ -79,7 +85,7 @@ class TestSizeCategoryLayerHelper(object):
         assert layer.style._style['line']['color'] == 'opacity(blue, 0.8)'
 
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             cat=['A', 'B'],
@@ -94,7 +100,7 @@ class TestSizeCategoryLayerHelper(object):
         "should show/hide the legend"
         setup_mocks(mocker)
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=False
         )
@@ -103,7 +109,7 @@ class TestSizeCategoryLayerHelper(object):
         assert layer.legend._title == ''
 
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=True
         )
@@ -119,7 +125,7 @@ class TestSizeCategoryLayerHelper(object):
         "should show/hide the popup"
         setup_mocks(mocker)
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=False
         )
@@ -127,7 +133,7 @@ class TestSizeCategoryLayerHelper(object):
         assert layer.popup._hover == []
 
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=True
         )
@@ -141,7 +147,7 @@ class TestSizeCategoryLayerHelper(object):
         "should show/hide the widget"
         setup_mocks(mocker)
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=False
         )
@@ -149,7 +155,7 @@ class TestSizeCategoryLayerHelper(object):
         assert layer.widgets._widgets == []
 
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=True
         )
@@ -161,7 +167,7 @@ class TestSizeCategoryLayerHelper(object):
         "should animate a property and disable the popups"
         setup_mocks(mocker)
         layer = helpers.size_category_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             animate='time'
         )
diff --git a/tests/unit/viz/helpers/test_size_continuous_layer.py b/tests/unit/viz/helpers/test_size_continuous_layer.py
index dc4cf376..42826ec6 100644
--- a/tests/unit/viz/helpers/test_size_continuous_layer.py
+++ b/tests/unit/viz/helpers/test_size_continuous_layer.py
@@ -1,9 +1,14 @@
 from cartoframes.viz import helpers
+from cartoframes.auth import Credentials
 
 from . import setup_mocks
+from ..utils import simple_dataframe
 
 
 class TestSizeContinuousLayerHelper(object):
+    def setup_method(self):
+        self.source = simple_dataframe()
+
     def test_helpers(self):
         "should be defined"
         assert helpers.size_continuous_layer is not None
@@ -12,8 +17,9 @@ class TestSizeContinuousLayerHelper(object):
         "should create a layer with the proper attributes"
         setup_mocks(mocker)
         layer = helpers.size_continuous_layer(
-            source='sf_neighborhoods',
-            value='name'
+            source='SELECT * FROM faketable',
+            value='name',
+            credentials=Credentials('fakeuser')
         )
 
         assert layer.style is not None
@@ -42,7 +48,7 @@ class TestSizeContinuousLayerHelper(object):
         "should create a point type layer"
         setup_mocks(mocker)
         layer = helpers.size_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             size=[10, 20],
@@ -57,7 +63,7 @@ class TestSizeContinuousLayerHelper(object):
         "should create a line type layer"
         setup_mocks(mocker, 'line')
         layer = helpers.size_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             'Neighborhoods',
             size=[10, 20],
@@ -72,7 +78,7 @@ class TestSizeContinuousLayerHelper(object):
         "should show/hide the legend"
         setup_mocks(mocker)
         layer = helpers.size_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=False
         )
@@ -81,7 +87,7 @@ class TestSizeContinuousLayerHelper(object):
         assert layer.legend._title == ''
 
         layer = helpers.size_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             legend=True
         )
@@ -97,7 +103,7 @@ class TestSizeContinuousLayerHelper(object):
         "should show/hide the popup"
         setup_mocks(mocker)
         layer = helpers.size_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=False
         )
@@ -105,7 +111,7 @@ class TestSizeContinuousLayerHelper(object):
         assert layer.popup._hover == []
 
         layer = helpers.size_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             popup=True
         )
@@ -119,7 +125,7 @@ class TestSizeContinuousLayerHelper(object):
         "should show/hide the widget"
         setup_mocks(mocker)
         layer = helpers.size_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=False
         )
@@ -127,7 +133,7 @@ class TestSizeContinuousLayerHelper(object):
         assert layer.widgets._widgets == []
 
         layer = helpers.size_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             widget=True
         )
@@ -139,7 +145,7 @@ class TestSizeContinuousLayerHelper(object):
         "should animate a property and disable the popups"
         setup_mocks(mocker)
         layer = helpers.size_continuous_layer(
-            'sf_neighborhoods',
+            self.source,
             'name',
             animate='time'
         )
diff --git a/tests/unit/viz/test_layer.py b/tests/unit/viz/test_layer.py
index 342ba2be..c48e2a27 100644
--- a/tests/unit/viz/test_layer.py
+++ b/tests/unit/viz/test_layer.py
@@ -1,9 +1,12 @@
 from cartoframes.viz import Layer, Legend, Popup, Source, Style
+from cartoframes.lib.context.api_context import APIContext
+from cartoframes.auth import Credentials
 
 
 def setup_mocks(mocker):
     mocker.patch.object(Source, 'get_geom_type', return_value='point')
     mocker.patch.object(Source, '_compute_query_bounds')
+    mocker.patch.object(APIContext, 'get_schema', return_value='public')
 
 
 class TestLayer(object):
@@ -14,7 +17,7 @@ class TestLayer(object):
     def test_initialization_objects(self, mocker):
         """Layer should initialize layer attributes"""
         setup_mocks(mocker)
-        layer = Layer(Source('layer_source'))
+        layer = Layer(Source('layer_source', credentials=Credentials('fakeuser')))
 
         assert layer.is_basemap is False
         assert layer.orig_query == 'SELECT * FROM "public"."layer_source"'
@@ -27,7 +30,7 @@ class TestLayer(object):
     def test_initialization_simple(self, mocker):
         """Layer should initialize layer attributes"""
         setup_mocks(mocker)
-        layer = Layer('layer_source', '')
+        layer = Layer('layer_source', '', credentials=Credentials('fakeuser'))
 
         assert layer.is_basemap is False
         assert layer.orig_query == 'SELECT * FROM "public"."layer_source"'
@@ -53,7 +56,8 @@ class TestLayerStyle(object):
                 'width': 10,
                 'strokeColor': 'black',
                 'strokeWidth': 1
-            }
+            },
+            credentials=Credentials('fakeuser')
         )
 
         assert isinstance(layer.style, Style)
@@ -74,7 +78,8 @@ class TestLayerStyle(object):
                 width: 10
                 strokeColor: black
                 strokeWidth: 1
-            """
+            """,
+            credentials=Credentials('fakeuser')
         )
 
         assert isinstance(layer.style, Style)
diff --git a/tests/unit/viz/utils.py b/tests/unit/viz/utils.py
index fd355f90..37f714c1 100644
--- a/tests/unit/viz/utils.py
+++ b/tests/unit/viz/utils.py
@@ -14,3 +14,7 @@ def build_geojson(lats, lngs):
     dataframe['Coordinates'] = dataframe['Coordinates'].apply(Point)
 
     return GeoDataFrame(dataframe, geometry='Coordinates')
+
+
+def simple_dataframe():
+    return DataFrame({'lat': [0], 'lng': [0]})