Skip to content

Commit d542fe1

Browse files
Merge pull request #856 from guzman-raphael/plugin_0_12_8
-> Plugin: Sync with release 0.12.8
2 parents 9127d47 + 2657185 commit d542fe1

27 files changed

+405
-178
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: 'bug, awaiting-triage'
6+
assignees: ''
7+
8+
---
9+
10+
## Bug Report
11+
12+
### Description
13+
A clear and concise description of what is the overall operation that is intended to be performed that resulted in an error.
14+
15+
### Reproducibility
16+
Include:
17+
- OS (WIN | MACOS | Linux)
18+
- Python Version OR MATLAB Version
19+
- MySQL Version
20+
- MySQL Deployment Strategy (local-native | local-docker | remote)
21+
- DataJoint Version
22+
- Minimum number of steps to reliably reproduce the issue
23+
- Complete error stack as a result of evaluating the above steps
24+
25+
### Expected Behavior
26+
A clear and concise description of what you expected to happen.
27+
28+
### Screenshots
29+
If applicable, add screenshots to help explain your problem.
30+
31+
### Additional Research and Context
32+
Add any additional research or context that was conducted in creating this report.
33+
34+
For example:
35+
- Related GitHub issues and PR's either within this repository or in other relevant repositories.
36+
- Specific links to specific lines or a focus within source code.
37+
- Relevant summary of Maintainers development meetings, milestones, projects, etc.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for a new feature
4+
title: ''
5+
labels: 'enhancement, awaiting-triage'
6+
assignees: ''
7+
8+
---
9+
10+
## Feature Request
11+
12+
### Problem
13+
A clear and concise description how this idea has manifested and the context. Elaborate on the need for this feature and/or what could be improved. Ex. I'm always frustrated when [...]
14+
15+
### Requirements
16+
A clear and concise description of the requirements to satisfy the new feature. Detail what you expect from a successful implementation of the feature. Ex. When using this feature, it should [...]
17+
18+
### Justification
19+
Provide the key benefits in making this a supported feature. Ex. Adding support for this feature would ensure [...]
20+
21+
### Alternative Considerations
22+
Do you currently have a work-around for this? Provide any alternative solutions or features you've considered.
23+
24+
### Related Errors
25+
Add any errors as a direct result of not exposing this feature.
26+
27+
Please include steps to reproduce provided errors as follows:
28+
- OS (WIN | MACOS | Linux)
29+
- Python Version OR MATLAB Version
30+
- MySQL Version
31+
- MySQL Deployment Strategy (local-native | local-docker | remote)
32+
- DataJoint Version
33+
- Minimum number of steps to reliably reproduce the issue
34+
- Complete error stack as a result of evaluating the above steps
35+
36+
### Screenshots
37+
If applicable, add screenshots to help explain your feature.
38+
39+
### Additional Research and Context
40+
Add any additional research or context that was conducted in creating this feature request.
41+
42+
For example:
43+
- Related GitHub issues and PR's either within this repository or in other relevant repositories.
44+
- Specific links to specific line or focus within source code.
45+
- Relevant summary of Maintainers development meetings, milestones, projects, etc.
46+
- Any additional supplemental web references or links that would further justify this feature request.

.github/workflows/development.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Development
2+
on:
3+
push:
4+
branches:
5+
- '**' # every branch
6+
- '!stage*' # exclude branches beginning with stage
7+
pull_request:
8+
branches:
9+
- '**' # every branch
10+
- '!stage*' # exclude branches beginning with stage
11+
jobs:
12+
test:
13+
if: github.event_name == 'push' || github.event_name == 'pull_request'
14+
runs-on: ubuntu-latest
15+
strategy:
16+
matrix:
17+
py_ver: ["3.8"]
18+
mysql_ver: ["8.0", "5.7", "5.6"]
19+
include:
20+
- py_ver: "3.7"
21+
mysql_ver: "5.7"
22+
- py_ver: "3.6"
23+
mysql_ver: "5.7"
24+
- py_ver: "3.5"
25+
mysql_ver: "5.7"
26+
steps:
27+
- uses: actions/checkout@v2
28+
- name: Set up Python ${{matrix.py_ver}}
29+
uses: actions/setup-python@v2
30+
with:
31+
python-version: ${{matrix.py_ver}}
32+
- name: Install dependencies
33+
run: |
34+
python -m pip install --upgrade pip
35+
pip install flake8
36+
- name: Run syntax tests
37+
run: flake8 datajoint --count --select=E9,F63,F7,F82 --show-source --statistics
38+
- name: Run primary tests
39+
env:
40+
UID: "1001"
41+
GID: "116"
42+
PY_VER: ${{matrix.py_ver}}
43+
MYSQL_VER: ${{matrix.mysql_ver}}
44+
ALPINE_VER: "3.10"
45+
MINIO_VER: RELEASE.2019-09-26T19-42-35Z
46+
COMPOSE_HTTP_TIMEOUT: "120"
47+
COVERALLS_SERVICE_NAME: travis-ci
48+
COVERALLS_REPO_TOKEN: fd0BoXG46TPReEem0uMy7BJO5j0w1MQiY
49+
run: docker-compose -f LNX-docker-compose.yml up --build --exit-code-from app
50+
- name: Run style tests
51+
run: |
52+
flake8 --ignore=E121,E123,E126,E226,E24,E704,W503,W504,E722,F401,W605 datajoint \
53+
--count --max-complexity=62 --max-line-length=127 --statistics

.travis.yml

Lines changed: 0 additions & 59 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
## Release notes
22

3+
### 0.12.8b1 -- Jan 12, 2021
4+
* table.children, .parents, .descendents, and ancestors can return queryable objects. PR #833
5+
* Load dependencies before querying dependencies. (#179) PR #833
6+
* Fix display of part tables in `schema.save`. (#821) PR #833
7+
* Add `schema.list_tables`. (#838) PR #844
8+
* Fix minio new version regression. PR #847
9+
* Add more S3 logging for debugging. (#831) PR #832
10+
* Convert testing framework from TravisCI to GitHub Actions (#841) PR #840
11+
312
### 0.12.7b1 -- Oct 27, 2020
413
* Fix case sensitivity issues to adapt to MySQL 8+. PR #819
514
* Fix pymysql regression bug (#814) PR #816

LNX-docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ services:
3232
interval: 1s
3333
fakeservices.datajoint.io:
3434
<<: *net
35-
image: raphaelguzman/nginx:v0.0.10
35+
image: raphaelguzman/nginx:v0.0.13
3636
environment:
3737
- ADD_db_TYPE=DATABASE
3838
- ADD_db_ENDPOINT=db:3306

datajoint/autopopulate.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,19 @@ def key_source(self):
3232
The default value is the join of the parent relations.
3333
Users may override to change the granularity or the scope of populate() calls.
3434
"""
35-
def parent_gen(self):
36-
if self.target.full_table_name not in self.connection.dependencies:
37-
self.connection.dependencies.load()
38-
for parent_name, fk_props in self.target.parents(primary=True).items():
39-
if not parent_name.isdigit(): # simple foreign key
40-
yield FreeTable(self.connection, parent_name).proj()
41-
else:
42-
grandparent = list(self.connection.dependencies.in_edges(parent_name))[0][0]
43-
yield FreeTable(self.connection, grandparent).proj(**{
44-
attr: ref for attr, ref in fk_props['attr_map'].items() if ref != attr})
35+
def _rename_attributes(table, props):
36+
return (table.proj(
37+
**{attr: ref for attr, ref in props['attr_map'].items() if attr != ref})
38+
if props['aliased'] else table)
4539

4640
if self._key_source is None:
47-
parents = parent_gen(self)
48-
try:
49-
self._key_source = next(parents)
50-
except StopIteration:
51-
raise DataJointError('A table must have primary dependencies for auto-populate to work')
52-
for q in parents:
53-
self._key_source *= q
41+
parents = self.target.parents(primary=True, as_objects=True, foreign_key_info=True)
42+
if not parents:
43+
raise DataJointError(
44+
'A relation must have primary dependencies for auto-populate to work')
45+
self._key_source = _rename_attributes(*parents[0])
46+
for q in parents[1:]:
47+
self._key_source *= _rename_attributes(*q)
5448
return self._key_source
5549

5650
def make(self, key):

datajoint/connection.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ def close(self):
195195

196196
def register(self, schema):
197197
self.schemas[schema.database] = schema
198+
self.dependencies.clear()
198199

199200
def ping(self):
200201
"""

datajoint/dependencies.py

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,36 @@
11
import networkx as nx
22
import itertools
3+
import re
34
from collections import defaultdict, OrderedDict
45
from .errors import DataJointError
56

67

8+
def unite_master_parts(lst):
9+
"""
10+
re-order a list of table names so that part tables immediately follow their master tables without breaking
11+
the topological order.
12+
Without this correction, a simple topological sort may insert other descendants between master and parts.
13+
The input list must be topologically sorted.
14+
:example:
15+
unite_master_parts(
16+
['`s`.`a`', '`s`.`a__q`', '`s`.`b`', '`s`.`c`', '`s`.`c__q`', '`s`.`b__q`', '`s`.`d`', '`s`.`a__r`']) ->
17+
['`s`.`a`', '`s`.`a__q`', '`s`.`a__r`', '`s`.`b`', '`s`.`b__q`', '`s`.`c`', '`s`.`c__q`', '`s`.`d`']
18+
"""
19+
for i in range(2, len(lst)):
20+
name = lst[i]
21+
match = re.match(r'(?P<master>`\w+`.`\w+)__\w+`', name)
22+
if match: # name is a part table
23+
master = match.group('master')
24+
for j in range(i-1, -1, -1):
25+
if lst[j] == master + '`' or lst[j].startswith(master + '__'):
26+
# move from the ith position to the (j+1)th position
27+
lst[j+1:i+1] = [name] + lst[j+1:i]
28+
break
29+
else:
30+
raise DataJointError("Found a part table {name} without its master table.".format(name=name))
31+
return lst
32+
33+
734
class Dependencies(nx.DiGraph):
835
"""
936
The graph of dependencies (foreign keys) between loaded tables.
@@ -16,15 +43,22 @@ class Dependencies(nx.DiGraph):
1643
def __init__(self, connection=None):
1744
self._conn = connection
1845
self._node_alias_count = itertools.count()
46+
self._loaded = False
1947
super().__init__(self)
2048

21-
def load(self):
49+
def clear(self):
50+
self._loaded = False
51+
super().clear()
52+
53+
def load(self, force=True):
2254
"""
2355
Load dependencies for all loaded schemas.
2456
This method gets called before any operation that requires dependencies: delete, drop, populate, progress.
2557
"""
26-
2758
# reload from scratch to prevent duplication of renamed edges
59+
if self._loaded and not force:
60+
return
61+
2862
self.clear()
2963

3064
# load primary key info
@@ -77,6 +111,7 @@ def load(self):
77111

78112
if not nx.is_directed_acyclic_graph(self): # pragma: no cover
79113
raise DataJointError('DataJoint can only work with acyclic dependencies')
114+
self._loaded = True
80115

81116
def parents(self, table_name, primary=None):
82117
"""
@@ -86,6 +121,7 @@ def parents(self, table_name, primary=None):
86121
attribute are considered.
87122
:return: dict of tables referenced by the foreign keys of table
88123
"""
124+
self.load(force=False)
89125
return {p[0]: p[2] for p in self.in_edges(table_name, data=True)
90126
if primary is None or p[2]['primary'] == primary}
91127

@@ -97,6 +133,7 @@ def children(self, table_name, primary=None):
97133
attribute are considered.
98134
:return: dict of tables referencing the table through foreign keys
99135
"""
136+
self.load(force=False)
100137
return {p[1]: p[2] for p in self.out_edges(table_name, data=True)
101138
if primary is None or p[2]['primary'] == primary}
102139

@@ -105,17 +142,19 @@ def descendants(self, full_table_name):
105142
:param full_table_name: In form `schema`.`table_name`
106143
:return: all dependent tables sorted in topological order. Self is included.
107144
"""
145+
self.load(force=False)
108146
nodes = self.subgraph(
109147
nx.algorithms.dag.descendants(self, full_table_name))
110-
return [full_table_name] + list(
111-
nx.algorithms.dag.topological_sort(nodes))
148+
return unite_master_parts([full_table_name] + list(
149+
nx.algorithms.dag.topological_sort(nodes)))
112150

113151
def ancestors(self, full_table_name):
114152
"""
115153
:param full_table_name: In form `schema`.`table_name`
116154
:return: all dependent tables sorted in topological order. Self is included.
117155
"""
156+
self.load(force=False)
118157
nodes = self.subgraph(
119158
nx.algorithms.dag.ancestors(self, full_table_name))
120-
return [full_table_name] + list(reversed(list(
121-
nx.algorithms.dag.topological_sort(nodes))))
159+
return list(reversed(unite_master_parts(list(
160+
nx.algorithms.dag.topological_sort(nodes)) + [full_table_name])))

0 commit comments

Comments
 (0)