-
Notifications
You must be signed in to change notification settings - Fork 90
External storage, enhancements, bugfixes #377
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
Changes from 1 commit
67e41ef
f89bf0e
159cb51
bb88117
9703126
4fa1abd
d6b9f2a
c35ed7a
7299058
3baf487
4969c36
ce774be
ad650b0
860d04b
2144b0f
cfc1e21
0195cfc
d821bcf
183b324
6164eb5
96f0d20
b37175b
9688e5d
bcc0048
28208c2
04b1829
1c8e071
bb11c1b
9fc36b4
9fca90f
7069dad
3bc28c5
a3d1a53
d9cca7b
1b37ee9
cf3cf0c
85b6587
f936073
2b622c1
5270d80
85502b0
bdba20d
919efba
e30dfb2
259950d
3a7f416
3594c67
7eb114c
4d1af79
4a58a9a
1ca0b09
add950f
90c021e
782a9a5
383595d
794dc47
5ab3381
4b2671e
9a0b902
7302571
569881a
86c2480
6f7c6bd
8018a9d
7627569
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -185,22 +185,31 @@ def compile_attribute(line, in_key, foreign_key_sql): | |
| match['default'] = 'NOT NULL' | ||
| match['comment'] = match['comment'].replace('"', '\\"') # escape double quotes in comment | ||
|
|
||
| is_external = match['type'] == 'external' | ||
| is_external = match['type'].startswith('external') | ||
| if not is_external: | ||
| sql = ('`{name}` {type} {default}' + (' COMMENT "{comment}"' if match['comment'] else '')).format(**match) | ||
| else: | ||
| # process externally stored attribute | ||
| if in_key: | ||
| raise DataJointError('External attributes cannot be primary in:\n%s' % line) | ||
| store_name = match['type'].split('-') | ||
| if store_name[0] != 'external': | ||
| raise DataJointError('External store types must be in format external-<name>') | ||
| store_name = '-'.join(store_name[1:]) | ||
| if not store_name.isidentifier(): | ||
|
||
| raise DataJointError( | ||
| 'The external store name `{type}` is invalid. Make like a python identifier.'.format(**match)) | ||
| if len(store_name)>STORE_NAME_LENGTH: | ||
| raise DataJointError( | ||
| 'The external store name `{type}` is too long. Must be <={max_len} characters.'.format( | ||
| max_len=STORE_NAME_LENGTH, **match)) | ||
| if not match['default'] in ('DEFAULT NULL', 'NOT NULL'): | ||
| raise DataJointError('The only acceptable default value for an external field is null in:\n%s' % line) | ||
| if match['type'] not in config: | ||
| raise DataJointError('The external store `{type}` is not configured.'.format(**match)) | ||
| if len(match['type']) > STORE_NAME_LENGTH + STORE_NAME_LENGTH + 1: | ||
| raise DataJointError( | ||
| 'The external store name `{type}` is too long. Must be <={max_len} characters.'.format( | ||
| max_len=STORE_NAME_LENGTH, **match)) | ||
| sql = "`_{name}` {hash_type} {default} COMMENT {comment:type}'".format( | ||
|
|
||
| # append external configuration name to the end of the comment | ||
| sql = '`_{name}` {hash_type} {default} COMMENT "{comment}:{type}"'.format( | ||
| hash_type=HASH_DATA_TYPE, **match) | ||
| foreign_key_sql.append( | ||
| "FOREIGN KEY (`_{name}`) REFERENCES {{external_table}} (`hash`) " | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| """ | ||
| a schema for testing external attributes | ||
| """ | ||
|
|
||
| import datajoint as dj | ||
|
|
||
| from . import PREFIX, CONN_INFO | ||
| import numpy as np | ||
|
|
||
| schema = dj.schema(PREFIX + '_extern', locals(), connection=dj.conn(**CONN_INFO)) | ||
|
|
||
|
|
||
| dj.config['external'] = { | ||
| 'protocol': 'file', | ||
| 'location': 'dj-store/external'} | ||
|
|
||
| dj.config['external-raw'] = { | ||
| 'protocol': 'file', | ||
| 'location': 'dj-store/raw'} | ||
|
|
||
| dj.config['external-compute'] = { | ||
| 'protocol': 's3', | ||
| 'location': '/datajoint-projects/test', | ||
| 'user': 'djtest', | ||
| 'token': '2e05709792545ce'} | ||
|
|
||
| dj.config['cache'] = { | ||
| 'protocol': 'file', | ||
| 'location': '/media/dimitri/ExtraDrive1/dj-store/cache'} | ||
|
|
||
|
|
||
|
|
||
| @schema | ||
| class Seed(dj.Lookup): | ||
| definition = """ | ||
| seed : int | ||
| """ | ||
| contents = zip(range(4)) | ||
|
|
||
|
|
||
| @schema | ||
| class Dimension(dj.Lookup): | ||
| definition = """ | ||
| dim : int | ||
| --- | ||
| dimensions : blob | ||
| """ | ||
| contents = ( | ||
| [0, [100, 50]], | ||
| [1, [3, 4, 8, 6]]) | ||
|
|
||
|
|
||
| @schema | ||
| class Image(dj.Manual): | ||
| definition = """ | ||
| # table for storing | ||
| -> Seed | ||
| -> Dimension | ||
| ---- | ||
| img : external-raw # objects are stored as specified by dj.config['external-raw'] | ||
| """ | ||
|
|
||
| def make(self, key): | ||
| np.random.seed(key['seed']) | ||
| self.insert1(dict(key, img=np.random.rand(*(Dimension() & key).fetch1('dimensions')))) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,36 +1,12 @@ | ||
| import numpy as np | ||
| from numpy.testing import assert_array_equal | ||
| from nose.tools import assert_true, assert_equal | ||
| import datajoint as dj | ||
| from datajoint.external import ExternalTable | ||
|
|
||
| from . import PREFIX, CONN_INFO | ||
| from . schema_external import schema | ||
|
|
||
|
|
||
| dj.config['external'] = { | ||
| 'protocol': 'file', | ||
| 'location': 'dj-store/external'} | ||
|
|
||
| dj.config['external-raw'] = { | ||
| 'protocol': 'file', | ||
| 'location': 'dj-store/raw'} | ||
|
|
||
| dj.config['external-compute'] = { | ||
| 'protocol': 's3', | ||
| 'location': '/datajoint-projects/test', | ||
| 'user': 'dimitri', | ||
| 'token': '2e05709792545ce' | ||
| } | ||
|
|
||
| dj.config['cache'] = { | ||
| 'protocol': 'file', | ||
| 'location': '/media/dimitri/ExtraDrive1/dj-store/cache'} | ||
|
|
||
|
|
||
| schema = dj.schema(PREFIX + '_external_test1', locals(), connection=dj.conn(**CONN_INFO)) | ||
|
|
||
|
|
||
| def test_external_put_get_remove(): | ||
| def test_external_put(): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. need to add test case for pure |
||
| """ | ||
| external storage put and get and remove | ||
| """ | ||
|
|
@@ -43,12 +19,8 @@ def test_external_put_get_remove(): | |
| for i in range(extra): | ||
| hash2 = ext.put('external-raw', np.random.randn(4, 3, 2)) | ||
|
|
||
| assert_true(hash1 in ext.fetch('hash')) | ||
| assert_equal(count, (ext & {'hash': hash1}).fetch1('count')) | ||
| assert_true(all(hash in ext.fetch('hash') for hash in (hash1, hash2))) | ||
| assert_equal(len(ext), 1 + extra) | ||
|
|
||
| output_ = ext.get(hash1) | ||
| assert_array_equal(input_, output_) | ||
|
|
||
| ext.remove(hash1) | ||
| assert_equal(count-1, (ext & {'hash': hash1}).fetch1('count')) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
|
|
||
| from nose.tools import assert_true, raises, assert_equal, assert_dict_equal | ||
|
|
||
| from . import schema_external as mod | ||
|
|
||
| def test_populate(): | ||
| print('here') | ||
| # mod.Image().populate() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should say
in format external vs external-<name>