Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let users never see Entry objects #490

Merged
merged 11 commits into from
May 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 5 additions & 6 deletions intake/catalog/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ def _get_entry(self, name):
entry = self._entries[name]
entry._catalog = self
entry._pmode = self.pmode
return entry
return entry()

@reload_on_change
def _get_entries(self):
Expand Down Expand Up @@ -380,7 +380,7 @@ def __getitem__(self, key):
e = self._entries[key]
e._catalog = self
e._pmode = self.pmode
return e
return e()
if isinstance(key, str) and '.' in key:
key = key.split('.')
if isinstance(key, list):
Expand All @@ -393,7 +393,7 @@ def __getitem__(self, key):
rest = '.'.join(parts)
try:
out = self._entries[prefix][rest]
return out
return out()
except KeyError:
# name conflict like "thing" and "think.oi", where it's
# the latter we are after
Expand All @@ -402,7 +402,7 @@ def __getitem__(self, key):
out = self
for part in key:
out = self[part]
return out
return out()
raise KeyError(key)

def discover(self):
Expand Down Expand Up @@ -768,8 +768,7 @@ def _data_to_source(cat, path, **kwargs):
if not isinstance(cat, Catalog):
raise NotImplementedError
out = {}
for name in cat:
entry = cat[name]
for name, entry in cat.items():
out[name] = entry.__getstate__()
out[name]['parameters'] = [up._captured_init_kwargs for up
in entry._user_parameters]
Expand Down
31 changes: 15 additions & 16 deletions intake/catalog/entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,12 @@ def __call__(self, persist=None, **kwargs):
s2 = s.get_persisted()
met = s2.metadata
if persist == 'always' or not met['ttl']:
return s2
if met['ttl'] < time.time() - met['timestamp']:
return s2
s = s2
elif met['ttl'] < time.time() - met['timestamp']:
s = s2
else:
return store.refresh(s2)
s = store.refresh(s2)
s._entry = self
return s

def _get_default_source(self):
Expand All @@ -94,6 +95,16 @@ def _get_default_source(self):
self._default_source = self()
return self._default_source

@property
def container(self):
return getattr(self, '_container', None)

@container.setter
def container(self, cont):
# so that .container (which sources always have) always reflects ._container,
# which is the variable name for entries.
self._container = cont

@property
def has_been_persisted(self, **kwargs):
"""For the source created with the given args, has it been persisted?"""
Expand All @@ -115,18 +126,6 @@ def _ipython_display_(self):
'application/json': {'root': contents["name"]}
}, raw=True)

def __getattr__(self, attr):
if attr in self.__dict__:
return self.__dict__[attr]
else:
return getattr(self._get_default_source(), attr)

def __dir__(self):
selflist = {'describe', 'describe_open', 'get', 'gui',
'has_been_persisted', 'plots'}
selflist.update(set(dir(self._get_default_source())))
return list(sorted(selflist))

def __iter__(self):
# If the entry is a catalog, this allows list(cat.entry)
if self._container == 'catalog':
Expand Down
6 changes: 3 additions & 3 deletions intake/catalog/tests/catalog1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ sources:
urlpath: '{{ CATALOG_DIR }}/entry1_{{ part }}.csv'
remote_env:
description: env gets interpreted in server
driver: csv
driver: intake.conftest.TestSource
args:
urlpath: 'path-{{intake_test}}'
parameters:
Expand Down Expand Up @@ -72,9 +72,9 @@ sources:
chunks: 5
datetime:
description: datetime parameters
driver: csv
driver: intake.conftest.TestSource
args:
time: "{{time}}"
urlpath: "{{time}}"
parameters:
time:
description: some time
Expand Down
6 changes: 6 additions & 0 deletions intake/catalog/tests/dot-nest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@ sources:
leaf:
description: leaf
driver: csv
args:
urlpath: ""
leafdot.dot:
description: leaf-dot
driver: csv
args:
urlpath: ""
leaf.dot:
description: leaf-dot
driver: csv
args:
urlpath: ""
61 changes: 29 additions & 32 deletions intake/catalog/tests/test_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,16 @@ def test_local_catalog(catalog1):
'metadata': {'foo': 'baz', 'bar': [2, 4, 6]},
'plugin': ['csv']
}
assert catalog1['entry1'].get().container == 'dataframe'
md = catalog1['entry1'].get().metadata
assert catalog1['entry1'].container == 'dataframe'
md = catalog1['entry1'].metadata
md.pop('catalog_dir')
assert md == dict(foo='bar', bar=[1, 2, 3])
assert md['foo'] == 'bar'
assert md['bar'] == [1, 2, 3]

# Use default parameters
assert catalog1['entry1_part'].get().container == 'dataframe'
assert catalog1['entry1_part'].container == 'dataframe'
# Specify parameters
assert catalog1['entry1_part'].get(part='2').container == 'dataframe'
assert catalog1['entry1_part'].configure_new(part='2').container == 'dataframe'


def test_get_items(catalog1):
Expand All @@ -82,9 +83,8 @@ def test_nested(catalog1):
assert catalog1.entry1.read().equals(catalog1.nested.nested.entry1.read())
assert 'nested.nested' not in catalog1.walk(depth=1)
assert 'nested.nested' in catalog1.walk(depth=2)
assert catalog1.nested._catalog == catalog1
assert catalog1.nested().cat == catalog1
assert catalog1.nested.nested.nested().cat.cat.cat is catalog1
assert catalog1.nested.cat == catalog1
assert catalog1.nested.nested.nested.cat.cat.cat is catalog1


def test_nested_gets_name_from_super(catalog1):
Expand Down Expand Up @@ -117,7 +117,7 @@ def test_metadata(catalog1):


def test_use_source_plugin_from_config(catalog1):
catalog1['use_example1'].get()
catalog1['use_example1']


def test_get_dir():
Expand Down Expand Up @@ -307,7 +307,7 @@ def test_union_catalog():

# Implied creation of data source
assert union_cat.entry1.container == 'dataframe'
md = union_cat.entry1._metadata
md = union_cat.entry1.describe()['metadata']
assert md == dict(foo='bar', bar=[1, 2, 3])

# Use default parameters in explict creation of data source
Expand Down Expand Up @@ -541,14 +541,12 @@ def test_multi_plugins():
def test_no_plugins():
fn = abspath('multi_plugins.yaml')
cat = open_catalog(fn)
s = cat.tables6
with pytest.raises(ValueError) as e:
s()
cat.tables6
assert 'doesnotexist' in str(e.value)
assert 'plugin-directory' in str(e.value)
s = cat.tables7
with pytest.raises(ValueError) as e:
s()
cat.tables7
assert 'doesnotexist' in str(e.value)


Expand Down Expand Up @@ -580,44 +578,43 @@ def test_getitem_and_getattr():
catalog.doesnotexit
with pytest.raises(AttributeError):
catalog._doesnotexit
assert catalog.tables0 is catalog['tables0']
assert isinstance(catalog.tables0, LocalCatalogEntry)
assert catalog.tables0 == catalog['tables0']
assert isinstance(catalog.metadata, (dict, type(None)))


def test_dot_names():
fn = abspath('dot-nest.yaml')
cat = open_catalog(fn)
assert cat.self.leaf._description == 'leaf'
assert cat.self['leafdot.dot']._description == 'leaf-dot'
assert cat['selfdot.dot', 'leafdot.dot']._description == 'leaf-dot'
assert cat.self.leaf.description == 'leaf'
assert cat.self['leafdot.dot'].description == 'leaf-dot'
assert cat['selfdot.dot', 'leafdot.dot'].description == 'leaf-dot'

assert cat['self.selfdot.dot', 'leafdot.dot']._description == 'leaf-dot'
assert cat['self.self.dot', 'leafdot.dot']._description == 'leaf-dot'
assert cat['self.self.dot', 'leaf']._description == 'leaf'
assert cat['self.self.dot', 'leaf.dot']._description == 'leaf-dot'
assert cat['self.selfdot.dot', 'leafdot.dot'].description == 'leaf-dot'
assert cat['self.self.dot', 'leafdot.dot'].description == 'leaf-dot'
assert cat['self.self.dot', 'leaf'].description == 'leaf'
assert cat['self.self.dot', 'leaf.dot'].description == 'leaf-dot'

assert cat['self.self.dot.leaf.dot']._description == 'leaf-dot'
assert cat['self.self.dot.leaf.dot'].description == 'leaf-dot'


def test_listing(catalog1):
assert list(catalog1) == list(catalog1.nested)
with pytest.raises(ValueError):
with pytest.raises(TypeError):
list(catalog1.arr)


def test_dict_save():
from intake.catalog.base import Catalog
fn = os.path.join(tempfile.mkdtemp(), 'mycat.yaml')
entry = LocalCatalogEntry(name='trial', description='get this back',
driver='csv')
driver='csv', args=dict(urlpath=""))
cat = Catalog.from_dict({'trial': entry}, name='mycat')
cat.save(fn)

cat2 = open_catalog(fn)
assert 'trial' in cat2
assert cat2.name == 'mycat'
assert cat2.trial._driver == 'csv'
assert "CSV" in cat2.trial.classname


def test_dict_save_complex():
Expand All @@ -641,27 +638,27 @@ def test_dict_save_complex():
def test_dict_adddel():
from intake.catalog.base import Catalog
entry = LocalCatalogEntry(name='trial', description='get this back',
driver='csv')
driver='csv', args=dict(urlpath=""))
cat = Catalog.from_dict({'trial': entry}, name='mycat')
assert 'trial' in cat
cat['trial2'] = entry
assert list(cat) == ['trial', 'trial2']
cat.pop('trial')
assert list(cat) == ['trial2']
assert cat['trial2'] is entry
assert cat['trial2'].describe() == entry.describe()


def test_filter():
from intake.catalog.base import Catalog
entry1 = LocalCatalogEntry(name='trial', description='get this back',
driver='csv')
driver='csv', args=dict(urlpath=""))
entry2 = LocalCatalogEntry(name='trial', description='pass this through',
driver='csv')
driver='csv', args=dict(urlpath=""))
cat = Catalog.from_dict({'trial1': entry1,
'trial2': entry2}, name='mycat')
cat2 = cat.filter(lambda e: 'pass' in e._description)
assert list(cat2) == ['trial2']
assert cat2.trial2 is entry2
assert cat2.trial2 == entry2()


def test_no_instance():
Expand Down