Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
70ca4ff
added Connection.__del__ for closing the connection
dimitri-yatsenko May 22, 2015
8156593
Add schema decorator factory function and start changing relation
eywalker May 30, 2015
db71b00
Merge branch 'decorator' of github.com:datajoint/datajoint-python
dimitri-yatsenko Jun 3, 2015
6a41328
Add ClassRelation
eywalker Jun 3, 2015
34caae3
Merge pull request #99 from eywalker/decorator
dimitri-yatsenko Jun 4, 2015
cf10ddb
Merge branch 'decorator' of github.com:datajoint/datajoint-python int…
dimitri-yatsenko Jun 4, 2015
a0eb885
moved the schema management functionality out of the Connection class
dimitri-yatsenko Jun 4, 2015
50df1a3
fixed BaseRelation.is_declared
dimitri-yatsenko Jun 4, 2015
9b70f57
made table_name a class property in the user relation classes
dimitri-yatsenko Jun 4, 2015
b86a578
Merge pull request #100 from dimitri-yatsenko/decorator
eywalker Jun 5, 2015
c2f7ce3
intermediate
fabiansinz Jun 8, 2015
6ec2f32
Merge pull request #101 from fabiansinz/decorator
dimitri-yatsenko Jun 8, 2015
69b5f42
* merged Relation and ClassLevelRelation
fabiansinz Jun 8, 2015
2593680
* decorator declares table
fabiansinz Jun 8, 2015
4097adb
* removed implicit commit handling
fabiansinz Jun 8, 2015
b6c3f96
first test runs without failing
fabiansinz Jun 8, 2015
0c52d6c
first test runs without failing
fabiansinz Jun 8, 2015
eda035b
13 tests pass
fabiansinz Jun 8, 2015
52d4100
instantiating Subject fails
fabiansinz Jun 8, 2015
ff14bdb
Merge branch 'decorator' of github.com:fabiansinz/datajoint-python in…
dimitri-yatsenko Jun 9, 2015
2f0971a
implemented lookup_name using eval
dimitri-yatsenko Jun 9, 2015
6265e68
moved from_camel_case to user_relations.py
dimitri-yatsenko Jun 9, 2015
a48e66f
minor cleanup
dimitri-yatsenko Jun 9, 2015
622fd56
intermediate: removed classmethods from Relation. Moved all declarati…
dimitri-yatsenko Jun 9, 2015
3b8420e
amending, removed remaining classmethods from Relation
dimitri-yatsenko Jun 9, 2015
dafcbbc
converted Heading.init_from_database into an instance method
dimitri-yatsenko Jun 9, 2015
76a94b4
fixed heading initialization
dimitri-yatsenko Jun 9, 2015
bab7460
implemented dj.Subordinate to support subtables
dimitri-yatsenko Jun 9, 2015
706dff0
In Relation, split table_info attribute into its parts; made declare(…
dimitri-yatsenko Jun 9, 2015
2b261fc
typo
dimitri-yatsenko Jun 9, 2015
de8f009
typo
dimitri-yatsenko Jun 9, 2015
c8b9400
debugged and optimized table declaration in declare.py
dimitri-yatsenko Jun 12, 2015
d0690f2
fixed primary key declaration
dimitri-yatsenko Jun 12, 2015
86abe76
fixed camel_case_test
fabiansinz Jun 13, 2015
ec458a0
many tests in test_relation work again
fabiansinz Jun 13, 2015
190a55f
Merge pull request #102 from dimitri-yatsenko/decorator
fabiansinz Jun 15, 2015
083704a
RelationalOperand.restriction now returns [] if empty
dimitri-yatsenko Jun 15, 2015
7ed1ba8
test
fabiansinz Jun 15, 2015
237f61e
fixed bug in restriction by dict
dimitri-yatsenko Jun 16, 2015
05d84fa
fetch1 now returns OrderedDict with correct order of attributes.
dimitri-yatsenko Jun 16, 2015
5ffacfe
merged
fabiansinz Jun 16, 2015
194f304
Merge branch 'decorator' of https://github.com/datajoint/datajoint-py…
fabiansinz Jun 16, 2015
ae2669b
dropped transaction from teardown in tests
fabiansinz Jun 16, 2015
43a9a4b
Merge branch 'decorator' of github.com:fabiansinz/datajoint-python in…
dimitri-yatsenko Jun 16, 2015
d547f83
added AutoPopulate.progress
dimitri-yatsenko Jun 16, 2015
d306042
added doc string to AutoPopulate.progress()
dimitri-yatsenko Jun 16, 2015
77ad63d
fixed bug in blob packing/unpacking
dimitri-yatsenko Jun 16, 2015
cf3f30d
bugfix in blob pack/unpack
dimitri-yatsenko Jun 16, 2015
066ca4c
fixed Dimitri's pull request
fabiansinz Jun 20, 2015
f6fe321
more tests and context manager
fabiansinz Jun 20, 2015
7cb1173
more tests
fabiansinz Jun 20, 2015
c311cd8
Merge pull request #107 from fabiansinz/decorator
eywalker Jun 23, 2015
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
27 changes: 5 additions & 22 deletions datajoint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
__version__ = "0.2"
__all__ = ['__author__', '__version__',
'Connection', 'Heading', 'Relation', 'FreeRelation', 'Not',
'Relation',
'Manual', 'Lookup', 'Imported', 'Computed',
'AutoPopulate', 'conn', 'DataJointError', 'blob']


Expand All @@ -15,26 +17,6 @@ class DataJointError(Exception):
pass


class TransactionError(DataJointError):
"""
Base class for errors specific to DataJoint internal operation.
"""
def __init__(self, msg, f, args=None, kwargs=None):
super(TransactionError, self).__init__(msg)
self.operations = (f, args if args is not None else tuple(),
kwargs if kwargs is not None else {})

def resolve(self):
f, args, kwargs = self.operations
return f(*args, **kwargs)


@property
def culprit(self):
return self.operations[0].__name__



# ----------- loads local configuration from file ----------------
from .settings import Config, CONFIGVAR, LOCALCONFIG, logger, log_levels
config = Config()
Expand All @@ -56,8 +38,9 @@ def culprit(self):
# ------------- flatten import hierarchy -------------------------
from .connection import conn, Connection
from .relation import Relation
from .user_relations import Manual, Lookup, Imported, Computed, Subordinate
from .autopopulate import AutoPopulate
from . import blob
from .relational_operand import Not
from .free_relation import FreeRelation
from .heading import Heading
from .heading import Heading
from .relation import schema
40 changes: 19 additions & 21 deletions datajoint/autopopulate.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .relational_operand import RelationalOperand
from . import DataJointError, TransactionError, Relation
from . import DataJointError, Relation
import abc
import logging

Expand Down Expand Up @@ -37,56 +37,54 @@ def _make_tuples(self, key):
def target(self):
return self

def populate(self, restriction=None, suppress_errors=False, reserve_jobs=False, max_attempts=10):
def populate(self, restriction=None, suppress_errors=False, reserve_jobs=False):
"""
rel.populate() calls rel._make_tuples(key) for every primary key in self.populate_relation
for which there is not already a tuple in rel.

:param restriction: restriction on rel.populate_relation - target
:param suppress_errors: suppresses error if true
:param reserve_jobs: currently not implemented
:param max_attempts: maximal number of times a TransactionError is caught before populate gives up
"""

assert not reserve_jobs, NotImplemented # issue #5
error_list = [] if suppress_errors else None
if not isinstance(self.populate_relation, RelationalOperand):
raise DataJointError('Invalid populate_relation value')

self.conn.cancel_transaction() # rollback previous transaction, if any
self.connection.cancel_transaction() # rollback previous transaction, if any

if not isinstance(self, Relation):
raise DataJointError('Autopopulate is a mixin for Relation and must therefore subclass Relation')
raise DataJointError(
'AutoPopulate is a mixin for Relation and must therefore subclass Relation')

unpopulated = (self.populate_relation - self.target) & restriction
for key in unpopulated.project():
self.conn.start_transaction()
self.connection.start_transaction()
if key in self.target: # already populated
self.conn.cancel_transaction()
self.connection.cancel_transaction()
else:
logger.info('Populating: ' + str(key))
try:
for attempts in range(max_attempts):
try:
self._make_tuples(dict(key))
break
except TransactionError as tr_err:
self.conn.cancel_transaction()
tr_err.resolve()
self.conn.start_transaction()
logger.info('Transaction error in {0:s}.'.format(tr_err.culprit))
else:
raise DataJointError(
'%s._make_tuples failed after %i attempts, giving up' % (self.__class__,max_attempts))
self._make_tuples(dict(key))
except Exception as error:
self.conn.cancel_transaction()
self.connection.cancel_transaction()
if not suppress_errors:
raise
else:
logger.error(error)
error_list.append((key, error))
else:
self.conn.commit_transaction()
self.connection.commit_transaction()
logger.info('Done populating.')
return error_list


def progress(self):
"""
report progress of populating this table
"""
total = len(self.populate_relation)
remaining = len(self.populate_relation - self.target)
print('Remaining %d of %d (%2.1f%%)' % (remaining, total, 100*remaining/total)
if remaining else 'Complete', flush=True)
45 changes: 24 additions & 21 deletions datajoint/blob.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import zlib
import collections
from collections import OrderedDict
import numpy as np
from . import DataJointError

mxClassID = collections.OrderedDict(
mxClassID = OrderedDict((
# see http://www.mathworks.com/help/techdoc/apiref/mxclassid.html
mxUNKNOWN_CLASS=None,
mxCELL_CLASS=None, # TODO: implement
mxSTRUCT_CLASS=None, # TODO: implement
mxLOGICAL_CLASS=np.dtype('bool'),
mxCHAR_CLASS=np.dtype('c'),
mxVOID_CLASS=None,
mxDOUBLE_CLASS=np.dtype('float64'),
mxSINGLE_CLASS=np.dtype('float32'),
mxINT8_CLASS=np.dtype('int8'),
mxUINT8_CLASS=np.dtype('uint8'),
mxINT16_CLASS=np.dtype('int16'),
mxUINT16_CLASS=np.dtype('uint16'),
mxINT32_CLASS=np.dtype('int32'),
mxUINT32_CLASS=np.dtype('uint32'),
mxINT64_CLASS=np.dtype('int64'),
mxUINT64_CLASS=np.dtype('uint64'),
mxFUNCTION_CLASS=None)
('mxUNKNOWN_CLASS', None),
('mxCELL_CLASS', None), # TODO: implement
('mxSTRUCT_CLASS', None), # TODO: implement
('mxLOGICAL_CLASS', np.dtype('bool')),
('mxCHAR_CLASS', np.dtype('c')),
('mxVOID_CLASS', None),
('mxDOUBLE_CLASS', np.dtype('float64')),
('mxSINGLE_CLASS', np.dtype('float32')),
('mxINT8_CLASS', np.dtype('int8')),
('mxUINT8_CLASS', np.dtype('uint8')),
('mxINT16_CLASS', np.dtype('int16')),
('mxUINT16_CLASS', np.dtype('uint16')),
('mxINT32_CLASS', np.dtype('int32')),
('mxUINT32_CLASS', np.dtype('uint32')),
('mxINT64_CLASS', np.dtype('int64')),
('mxUINT64_CLASS', np.dtype('uint64')),
('mxFUNCTION_CLASS', None)))

reverseClassID = {v: i for i, v in enumerate(mxClassID.values())}
dtypeList = list(mxClassID.values())


def pack(obj):
Expand All @@ -41,6 +42,7 @@ def pack(obj):
obj, imaginary = np.real(obj), np.imag(obj)

type_number = reverseClassID[obj.dtype]
assert dtypeList[type_number] is obj.dtype, 'ambigous or unknown array type'
blob += np.asarray(type_number, dtype=np.uint32).tostring()
blob += np.int8(is_complex).tostring() + b'\0\0\0'
blob += obj.tostring()
Expand Down Expand Up @@ -72,9 +74,10 @@ def unpack(blob):
p += 8
array_shape = np.fromstring(blob[p:p+8*dimensions], dtype=np.uint64)
p += 8 * dimensions
mx_type, dtype = [q for q in mxClassID.items()][np.fromstring(blob[p:p+4], dtype=np.uint32)[0]]
type_number = np.fromstring(blob[p:p+4], dtype=np.uint32)[0]
dtype = dtypeList[type_number]
if dtype is None:
raise DataJointError('Unsupported MATLAB data type '+mx_type+' in blob')
raise DataJointError('Unsupported MATLAB data type '+type_number+' in blob')
p += 4
is_complex = np.fromstring(blob[p:p+4], dtype=np.uint32)[0]
p += 4
Expand Down
Loading