Skip to content

Commit 52562fe

Browse files
Merge branch 'master' of https://github.com/datajoint/datajoint-python into revamp-delete
2 parents 0048701 + 260b532 commit 52562fe

File tree

14 files changed

+80
-24
lines changed

14 files changed

+80
-24
lines changed

datajoint/autopopulate.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ def _jobs_to_do(self, restrictions):
6969
"""
7070
:return: the relation containing the keys to be computed (derived from self.key_source)
7171
"""
72+
if self.restriction:
73+
raise DataJointError('Cannot call populate on a restricted table. '
74+
'Instead, pass conditions to populate() as arguments.')
7275
todo = self.key_source
7376
if not isinstance(todo, RelationalOperand):
7477
raise DataJointError('Invalid key_source value')

datajoint/base_relation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ def describe(self, printout=True):
463463
class_name=lookup_class_name(parent_name, self.context) or parent_name)
464464
else:
465465
# aliased foreign key
466-
parent_name = self.connection.dependencies.in_edges(parent_name)[0][0]
466+
parent_name = list(self.connection.dependencies.in_edges(parent_name))[0][0]
467467
lst = [(attr, ref) for attr, ref in fk_props['attr_map'].items() if ref != attr]
468468
definition += '({attr_list}) -> {class_name}{ref_list}\n'.format(
469469
attr_list=','.join(r[0] for r in lst),

datajoint/connection.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,8 @@ def query(self, query, args=(), as_dict=False, suppress_warnings=True):
122122
cursor = client.cursors.DictCursor if as_dict else client.cursors.Cursor
123123
cur = self._conn.cursor(cursor=cursor)
124124

125+
logger.debug("Executing SQL:" + query[0:300])
125126
try:
126-
# Log the query
127-
logger.debug("Executing SQL:" + query[0:300])
128-
129127
with warnings.catch_warnings():
130128
if suppress_warnings:
131129
# suppress all warnings arising from underlying SQL library
@@ -144,9 +142,11 @@ def query(self, query, args=(), as_dict=False, suppress_warnings=True):
144142
else:
145143
raise
146144
except err.ProgrammingError as e:
147-
print('Error in query:')
148-
print(query)
149-
raise
145+
raise DataJointError("\n".join((
146+
"Error in query:", query,
147+
"Please check spelling, syntax, and existence of tables and attributes.",
148+
"When restricting a relation by a condition in a string, enclose attributes in backquotes."
149+
)))
150150
return cur
151151

152152
def get_user(self):

datajoint/dependencies.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@
77
class Dependencies(nx.DiGraph):
88
"""
99
The graph of dependencies (foreign keys) between loaded tables.
10+
11+
Note: the 'connnection' argument should normally be supplied;
12+
Empty use is permitted to facilliate use of networkx algorithms which
13+
internally create objects with the expectation of empty constructors.
14+
See also: https://github.com/datajoint/datajoint-python/pull/443
1015
"""
11-
def __init__(self, connection):
16+
def __init__(self, connection=None):
1217
self._conn = connection
1318
self._node_alias_count = itertools.count()
1419
super().__init__(self)
@@ -100,5 +105,9 @@ def descendants(self, full_table_name):
100105
:param full_table_name: In form `schema`.`table_name`
101106
:return: all dependent tables sorted in topological order. Self is included.
102107
"""
103-
nodes = nx.algorithms.dag.descendants(self, full_table_name)
104-
return [full_table_name] + nx.algorithms.dag.topological_sort(self, nodes)
108+
109+
nodes = self.subgraph(
110+
nx.algorithms.dag.descendants(self, full_table_name))
111+
112+
return [full_table_name] + list(
113+
nx.algorithms.dag.topological_sort(nodes))

datajoint/erd.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ def _make_graph(self):
206206
nx.algorithms.boundary.node_boundary(nx.DiGraph(self).reverse(), self.nodes_to_show))
207207
nodes = self.nodes_to_show.union(a for a in gaps if a.isdigit)
208208
# construct subgraph and rename nodes to class names
209-
graph = nx.DiGraph(self).subgraph(nodes)
210-
nx.set_node_attributes(graph, 'node_type', {n: _get_tier(n) for n in graph})
209+
graph = nx.DiGraph(nx.DiGraph(self).subgraph(nodes))
210+
nx.set_node_attributes(graph, name='node_type', values={n: _get_tier(n) for n in graph})
211211
# relabel nodes to class names
212212
clean_context = dict((k, v) for k, v in self.context.items()
213213
if not k.startswith('_')) # exclude ipython's implicit variables

datajoint/external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ def get(self, blob_hash):
7777
get an object from external store.
7878
Does not need to check whether it's in the table.
7979
"""
80+
if blob_hash is None:
81+
return None
8082
store = blob_hash[STORE_HASH_LENGTH:]
8183
store = 'external' + ('-' if store else '') + store
8284

@@ -184,4 +186,3 @@ def _get_store_spec(store):
184186
raise DataJointError(
185187
'Unknown external storage protocol "{protocol}" in "{store}"'.format(store=store, **spec))
186188
return spec
187-

datajoint/jobs.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from _decimal import Decimal
12
from .hash import key_hash
23
import os
34
import pymysql
@@ -58,6 +59,13 @@ def drop(self):
5859
"""bypass interactive prompts and dependencies"""
5960
self.drop_quick()
6061

62+
@staticmethod
63+
def packable_or_none(key):
64+
for v in key.values():
65+
if isinstance(v, Decimal):
66+
return None
67+
return key
68+
6169
def reserve(self, table_name, key):
6270
"""
6371
Reserve a job for computation. When a job is reserved, the job table contains an entry for the
@@ -73,7 +81,7 @@ def reserve(self, table_name, key):
7381
host=os.uname().nodename,
7482
pid=os.getpid(),
7583
connection_id=self.connection.connection_id,
76-
key=key,
84+
key=self.packable_or_none(key),
7785
user=self._user)
7886
try:
7987
self.insert1(job, ignore_extra_fields=True)
@@ -109,7 +117,7 @@ def error(self, table_name, key, error_message, error_stack=None):
109117
pid=os.getpid(),
110118
connection_id=self.connection.connection_id,
111119
user=self._user,
112-
key=key,
120+
key=self.packable_or_none(key),
113121
error_message=error_message,
114122
error_stack=error_stack),
115123
replace=True, ignore_extra_fields=True)

datajoint/s3.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ def __init__(self, endpoint, bucket, access_key, secret_key, location, database,
1616
self.bucket = bucket
1717
self.remote_path = '/'.join((location.lstrip('/'), database))
1818

19-
def make_bucket(self):
20-
self.client.make_bucket(self.bucket)
21-
2219
def put(self, blob_hash, blob):
2320
try:
2421
self.client.put_object(self.bucket, '/'.join((self.remote_path, blob_hash)), BytesIO(blob), len(blob))

datajoint/user_relations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
# attributes that trigger instantiation of user classes
1414
supported_class_attrs = set((
15-
'key_source', 'describe', 'populate', 'progress',
15+
'key_source', 'describe', 'populate', 'progress', 'primary_key',
1616
'proj', 'aggr', 'heading', 'fetch', 'fetch1',
1717
'insert', 'insert1', 'drop', 'drop_quick',
1818
'delete', 'delete_quick'))

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ pymysql>=0.7.2
33
pyparsing
44
ipython
55
tqdm
6-
networkx~=1.11
7-
pydotplus
6+
networkx
7+
pydot
88
minio

0 commit comments

Comments
 (0)