Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ dash_auth==1.4.1
dash_core_components==1.15.0
dash_html_components==1.1.2
dash_renderer==1.9.0
Werkzeug<=2.0.3
solvebio==2.12.0
pyyaml==5.3.1
click==7.1.2
ruamel.yaml==0.16.12
pytest
pytest
39 changes: 32 additions & 7 deletions solvebio/global_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def __init__(
query=None,
filters=None,
entities=None,
entities_match='any',
vault_scope='all',
ordering=None,
limit=float('inf'),
page_size=QueryBase.DEFAULT_PAGE_SIZE,
Expand All @@ -37,6 +39,8 @@ def __init__(
- `query` (optional): An optional query string (advanced search).
- `filters` (optional): Filter or List of filter objects.
- `entities` (optional): List of entity tuples to filter on (entity type, entity).
- `entities_match` (optional): Can be 'all' or 'any' (match any provided entity).
- `vault_scope` (optional): Can be 'all' or 'access'.
- `ordering` (optional): List of fields to order the results by.
- `limit` (optional): Maximum number of query results to return.
- `page_size` (optional): Number of results to fetch per query page.
Expand All @@ -49,12 +53,13 @@ def __init__(
self._data_url = '/v2/search'
self._query = query
self._entities = entities
self._entities_match = entities_match
self._vault_scope = vault_scope
self._ordering = ordering
self._result_class = result_class
self._debug = debug
self._raw_results = raw_results
self._error = None
self._is_join = False

if filters:
if isinstance(filters, Filter):
Expand Down Expand Up @@ -97,6 +102,8 @@ def _clone(self, filters=None, entities=None, limit=None):
ordering=self._ordering,
page_size=self._page_size,
result_class=self._result_class,
vault_scope=self._vault_scope,
entities_match=self._entities_match,
debug=self._debug,
client=self._client)
new._filters += self._filters
Expand Down Expand Up @@ -124,9 +131,6 @@ def __len__(self):
SELECT * FROM <table> [WHERE condition] [LIMIT number]
)
"""
if self._is_join:
return len(self._buffer)

return super(GlobalSearch, self).__len__()

def _build_query(self, **kwargs):
Expand All @@ -148,6 +152,12 @@ def _build_query(self, **kwargs):
if self._ordering is not None:
q['ordering'] = self._ordering

if self._vault_scope is not None:
q['vault_scope'] = self._vault_scope

if self._entities_match is not None:
q['entities_match'] = self._entities_match

if self._debug:
q['debug'] = 'True'

Expand All @@ -158,14 +168,20 @@ def _build_query(self, **kwargs):
return q

def execute(self, offset=0, **query):
def _process_result(result):
# Internally the client uses object_type, not type
result['object_type'] = result['type']
if result['object_type'] == 'vault':
return Vault.construct_from(result)
else:
return Object.construct_from(result)

# Call superclass method execute
super(GlobalSearch, self).execute(offset, **query)

# Cast logical objects from response to Object/Vault instances
if not self._raw_results:
self._response['results'] = [Vault.construct_from(result) if result['type'] == 'vault'
else Object.construct_from(result)
for result in self._response['results']]
self._response['results'] = [_process_result(i) for i in self._response['results']]

def entity(self, **kwargs):
"""
Expand Down Expand Up @@ -198,3 +214,12 @@ def subjects_count(self):
gs.execute()

return gs._response.get('subjects_count')

def vaults(self):
"""Returns the list of vaults"""

# Executes a query to get a full API response which contains vaults list
gs = self.limit(0)
gs.execute(include_vaults=True)

return gs._response.get('vaults')
11 changes: 4 additions & 7 deletions solvebio/resource/object.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,12 +440,9 @@ def __getattr__(self, name):
try:
return self[name]
except KeyError as err:
# If the Object has a dataset_id, it is of object_type "dataset"
# If there is no dataset_id, either this Object is a file or folder
# or the resource has not yet been retrieved from the API.
if name in valid_dataset_attrs and self.dataset_id:
if name in valid_dataset_attrs and self['object_type'] == "dataset":
return getattr(
Dataset(self.dataset_id, client=self._client), name)
Dataset(self['id'], client=self._client), name)

raise AttributeError(*err.args)

Expand All @@ -458,7 +455,7 @@ def dataset(self):
"Only dataset objects have a Dataset resource. This is a {}"
.format(self.object_type))

return Dataset.retrieve(self.dataset_id, client=self._client)
return Dataset.retrieve(self['id'], client=self._client)

@property
def parent(self):
Expand Down Expand Up @@ -560,7 +557,7 @@ def query(self, **params):
from solvebio.query import QueryFile

if self.is_dataset:
return Dataset(self.dataset_id, client=self._client).query(**params)
return Dataset(self['id'], client=self._client).query(**params)
elif self.is_file:
return QueryFile(self['id'], client=self._client, **params)
else:
Expand Down
8 changes: 4 additions & 4 deletions solvebio/test/test_dataset_migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ def test_migration_target_dataset_object(self, Create):
"""Target is an Object of object_type=dataset"""
Create.side_effect = fake_migration_create

source = self.client.Object(1, object_type='dataset')
source.dataset_id = source.id
target = self.client.Object(2, object_type='dataset')
target.dataset_id = target.id
source = self.client.Object(1)
source['object_type'] = 'dataset'
target = self.client.Object(2)
target['object_type'] = 'dataset'
migration = source.migrate(target=target, follow=False)
self.assertEqual(migration.source_id, source.id)
self.assertEqual(migration.target_id, target.id)
Expand Down