Skip to content

Commit 0d06ca4

Browse files
authored
Merge pull request #787 from guzman-raphael/plugin
Plugin: Merge in 0.12.6 and prepare for release 0.12.6b1
2 parents bb20ead + b432c01 commit 0d06ca4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+423
-483
lines changed

.dockerignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
notebook
2+
build
3+
*.egg-info
4+
dist
5+
.vscode
6+
__pycache__

.travis.yml

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,20 @@ env:
1111
services:
1212
- docker
1313
main: &main
14-
stage: Alpine
14+
stage: "Tests & Coverage: Alpine"
1515
os: linux
1616
dist: xenial # precise, trusty, xenial, bionic
1717
language: shell
1818
script:
1919
- docker-compose -f LNX-docker-compose.yml up --build --exit-code-from app
2020
jobs:
2121
include:
22+
- stage: "Lint: Syntax"
23+
language: python
24+
install:
25+
- pip install flake8
26+
script:
27+
- flake8 datajoint --count --select=E9,F63,F7,F82 --show-source --statistics
2228
- <<: *main
2329
env:
2430
- PY_VER: "3.8"
@@ -39,31 +45,15 @@ jobs:
3945
env:
4046
- PY_VER: "3.8"
4147
- MYSQL_VER: "8.0"
42-
- <<: *main
43-
env:
44-
- PY_VER: "3.7"
45-
- MYSQL_VER: "8.0"
46-
- <<: *main
47-
env:
48-
- PY_VER: "3.6"
49-
- MYSQL_VER: "8.0"
50-
- <<: *main
51-
env:
52-
- PY_VER: "3.5"
53-
- MYSQL_VER: "8.0"
5448
- <<: *main
5549
env:
5650
- PY_VER: "3.8"
5751
- MYSQL_VER: "5.6"
58-
- <<: *main
59-
env:
60-
- PY_VER: "3.7"
61-
- MYSQL_VER: "5.6"
62-
- <<: *main
63-
env:
64-
- PY_VER: "3.6"
65-
- MYSQL_VER: "5.6"
66-
- <<: *main
67-
env:
68-
- PY_VER: "3.5"
69-
- MYSQL_VER: "5.6"
52+
- stage: "Lint: Style"
53+
language: python
54+
install:
55+
- pip install flake8
56+
script:
57+
- |
58+
flake8 --ignore=E121,E123,E126,E226,E24,E704,W503,W504,E722,F401,W605 datajoint \
59+
--count --max-complexity=62 --max-line-length=127 --statistics

CHANGELOG.md

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

3+
### 0.12.6b1 -- May 18, 2020
4+
* Add `order_by` to `dj.kill` (#668, #779) PR #775, #783
5+
* Add explicit S3 bucket and file storage location existence checks (#748) PR #781
6+
* Modify `_update` to allow nullable updates for strings/date (#664) PR #760
7+
* Avoid logging events on auxiliary tables (#737) PR #753
8+
* Add `kill_quick` and expand display to include host (#740) PR #741
9+
* Bugfix - pandas insert fails due to additional `index` field (#666) PR #776
10+
* Bugfix - `delete_external_files=True` does not remove from S3 (#686) PR #781
11+
* Bugfix - pandas fetch throws error when `fetch_format='frame'` PR #774
12+
313
### 0.12.5b1 -- Feb 27, 2020
414
* Support DataJoint datatype and connection plugins (#715, #729) PR 730, #735
515

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
FROM datajoint/pydev
22

3-
ADD . /src
4-
RUN pip install /src && \
5-
rm -rf /src
3+
COPY --chown=dja . /tmp/src
4+
RUN pip install --user /tmp/src && \
5+
rm -rf /tmp/src

LNX-docker-compose.yml

Lines changed: 47 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,55 @@ x-net: &net
33
networks:
44
- main
55
services:
6-
app:
6+
db:
77
<<: *net
8-
image: datajoint/pydev:${PY_VER}-alpine${ALPINE_VER}
8+
image: datajoint/mysql:$MYSQL_VER
9+
environment:
10+
- MYSQL_ROOT_PASSWORD=simple
11+
# ports:
12+
# - "3306:3306"
13+
# volumes:
14+
# - ./mysql/data:/var/lib/mysql
15+
minio:
16+
<<: *net
17+
image: minio/minio:$MINIO_VER
18+
environment:
19+
- MINIO_ACCESS_KEY=datajoint
20+
- MINIO_SECRET_KEY=datajoint
21+
# ports:
22+
# - "9000:9000"
23+
# volumes:
24+
# - ./minio/config:/root/.minio
25+
# - ./minio/data:/data
26+
command: server --address ":9000" /data
27+
healthcheck:
28+
test: ["CMD", "curl", "--fail", "http://minio:9000/minio/health/live"]
29+
timeout: 5s
30+
retries: 60
31+
interval: 1s
32+
fakeservices.datajoint.io:
33+
<<: *net
34+
image: raphaelguzman/nginx:v0.0.6
35+
environment:
36+
- ADD_db_TYPE=DATABASE
37+
- ADD_db_ENDPOINT=db:3306
38+
- ADD_minio_TYPE=MINIO
39+
- ADD_minio_ENDPOINT=minio:9000
40+
- ADD_minio_PORT=80 # allow unencrypted connections
41+
- ADD_minio_PREFIX=/datajoint
42+
# ports:
43+
# - "80:80"
44+
# - "443:443"
45+
# - "3306:3306"
946
depends_on:
1047
db:
1148
condition: service_healthy
1249
minio:
1350
condition: service_healthy
51+
app:
52+
<<: *net
53+
image: datajoint/pydev:${PY_VER}-alpine${ALPINE_VER}
54+
depends_on:
1455
fakeservices.datajoint.io:
1556
condition: service_healthy
1657
environment:
@@ -20,10 +61,10 @@ services:
2061
- DJ_TEST_HOST=fakeservices.datajoint.io
2162
- DJ_TEST_USER=datajoint
2263
- DJ_TEST_PASSWORD=datajoint
23-
- S3_ENDPOINT=fakeservices.datajoint.io:9000
64+
- S3_ENDPOINT=fakeservices.datajoint.io
2465
- S3_ACCESS_KEY=datajoint
2566
- S3_SECRET_KEY=datajoint
26-
- S3_BUCKET=datajoint-test
67+
- S3_BUCKET=datajoint.test
2768
- PYTHON_USER=dja
2869
- JUPYTER_PASSWORD=datajoint
2970
- DISPLAY
@@ -35,8 +76,8 @@ services:
3576
"
3677
pip install --user nose nose-cov coveralls .;
3778
pip freeze | grep datajoint;
38-
coveralls;
39-
nosetests -vsw tests --with-coverage --cover-package=datajoint;
79+
nosetests -vsw tests --with-coverage --cover-package=datajoint && coveralls;
80+
# jupyter notebook;
4081
"
4182
# ports:
4283
# - "8888:8888"
@@ -45,55 +86,5 @@ services:
4586
- .:/src
4687
- /tmp/.X11-unix:/tmp/.X11-unix:rw
4788
# - ./notebooks:/home/dja/notebooks
48-
db:
49-
<<: *net
50-
image: datajoint/mysql:$MYSQL_VER
51-
environment:
52-
- MYSQL_ROOT_PASSWORD=simple
53-
# ports:
54-
# - "3306:3306"
55-
# volumes:
56-
# - ./mysql/data:/var/lib/mysql
57-
minio:
58-
<<: *net
59-
image: minio/minio:$MINIO_VER
60-
environment:
61-
- MINIO_ACCESS_KEY=datajoint
62-
- MINIO_SECRET_KEY=datajoint
63-
# ports:
64-
# - "9000:9000"
65-
# volumes:
66-
# - ./minio/config:/root/.minio
67-
# - ./minio/data:/data
68-
command: server /data
69-
healthcheck:
70-
test: ["CMD", "curl", "--fail", "http://minio:9000/minio/health/live"]
71-
timeout: 5s
72-
retries: 60
73-
interval: 1s
74-
fakeservices.datajoint.io:
75-
<<: *net
76-
image: nginx:alpine
77-
environment:
78-
- URL=datajoint.io
79-
- SUBDOMAINS=fakeservices
80-
- MINIO_SERVER=http://minio:9000
81-
- MYSQL_SERVER=db:3306
82-
entrypoint: /entrypoint.sh
83-
healthcheck:
84-
test: wget --quiet --tries=1 --spider https://fakeservices.datajoint.io:443/minio/health/live || exit 1
85-
timeout: 5s
86-
retries: 300
87-
interval: 1s
88-
# ports:
89-
# - "9000:9000"
90-
# - "443:443"
91-
# - "3306:3306"
92-
volumes:
93-
- ./tests/nginx/base.conf:/base.conf
94-
- ./tests/nginx/nginx.conf:/nginx.conf
95-
- ./tests/nginx/entrypoint.sh:/entrypoint.sh
96-
- ./tests/nginx/fullchain.pem:/certs/fullchain.pem
97-
- ./tests/nginx/privkey.pem:/certs/privkey.pem
9889
networks:
9990
main:

datajoint/admin.py

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,38 @@ def set_password(new_password=None, connection=None, update_config=None): # pr
2121
config.save_local(verbose=True)
2222

2323

24-
def kill(restriction=None, connection=None): # pragma: no cover
24+
def kill(restriction=None, connection=None, order_by=None): # pragma: no cover
2525
"""
2626
view and kill database connections.
2727
:param restriction: restriction to be applied to processlist
2828
:param connection: a datajoint.Connection object. Default calls datajoint.conn()
29+
:param order_by: order by a single attribute or the list of attributes. defaults to 'id'.
2930
3031
Restrictions are specified as strings and can involve any of the attributes of
3132
information_schema.processlist: ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO.
3233
3334
Examples:
3435
dj.kill('HOST LIKE "%compute%"') lists only connections from hosts containing "compute".
35-
dj.kill('TIME > 600') lists only connections older than 10 minutes.
36+
dj.kill('TIME > 600') lists only connections in their current state for more than 10 minutes
3637
"""
3738

3839
if connection is None:
3940
connection = conn()
4041

42+
if order_by is not None and not isinstance(order_by, str):
43+
order_by = ','.join(order_by)
44+
4145
query = 'SELECT * FROM information_schema.processlist WHERE id <> CONNECTION_ID()' + (
42-
"" if restriction is None else ' AND (%s)' % restriction)
46+
"" if restriction is None else ' AND (%s)' % restriction) + (
47+
' ORDER BY %s' % (order_by or 'id'))
4348

4449
while True:
45-
print(' ID USER STATE TIME INFO')
46-
print('+--+ +----------+ +-----------+ +--+')
50+
print(' ID USER HOST STATE TIME INFO')
51+
print('+--+ +----------+ +-----------+ +-----------+ +-----+')
4752
cur = connection.query(query, as_dict=True)
4853
for process in cur:
4954
try:
50-
print('{ID:>4d} {USER:<12s} {STATE:<12s} {TIME:>5d} {INFO}'.format(**process))
55+
print('{ID:>4d} {USER:<12s} {HOST:<12s} {STATE:<12s} {TIME:>7d} {INFO}'.format(**process))
5156
except TypeError:
5257
print(process)
5358
response = input('process to kill or "q" to quit > ')
@@ -63,3 +68,29 @@ def kill(restriction=None, connection=None): # pragma: no cover
6368
connection.query('kill %d' % pid)
6469
except pymysql.err.InternalError:
6570
print('Process not found')
71+
72+
73+
def kill_quick(restriction=None, connection=None):
74+
"""
75+
Kill database connections without prompting. Returns number of terminated connections.
76+
:param restriction: restriction to be applied to processlist
77+
:param connection: a datajoint.Connection object. Default calls datajoint.conn()
78+
79+
Restrictions are specified as strings and can involve any of the attributes of
80+
information_schema.processlist: ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO.
81+
82+
Examples:
83+
dj.kill('HOST LIKE "%compute%"') terminates connections from hosts containing "compute".
84+
"""
85+
if connection is None:
86+
connection = conn()
87+
88+
query = 'SELECT * FROM information_schema.processlist WHERE id <> CONNECTION_ID()' + (
89+
"" if restriction is None else ' AND (%s)' % restriction)
90+
91+
cur = connection.query(query, as_dict=True)
92+
nkill = 0
93+
for process in cur:
94+
connection.query('kill %d' % process['ID'])
95+
nkill += 1
96+
return nkill

datajoint/attribute_adapter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def get_adapter(context, adapter_name):
4040
adapter_name = adapter_name.lstrip('<').rstrip('>')
4141
try:
4242
adapter = (context[adapter_name] if adapter_name in context
43-
else type_plugins[adapter_name]['object'].load())
43+
else type_plugins[adapter_name]['object'].load())
4444
except KeyError:
4545
raise DataJointError(
4646
"Attribute adapter '{adapter_name}' is not defined.".format(adapter_name=adapter_name))

datajoint/autopopulate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import random
66
import inspect
77
from tqdm import tqdm
8-
from .expression import QueryExpression, AndList, U
8+
from .expression import QueryExpression, AndList
99
from .errors import DataJointError, LostConnectionError
1010
from .table import FreeTable
1111
import signal

datajoint/blob.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,11 @@ def __init__(self, squeeze=False):
7373

7474
def set_dj0(self):
7575
if not config.get('enable_python_native_blobs'):
76-
raise DataJointError('v0.12+ python native blobs disabled. see also: https://github.com/datajoint/datajoint-python#python-native-blobs')
76+
raise DataJointError("""v0.12+ python native blobs disabled.
77+
See also: https://github.com/datajoint/datajoint-python#python-native-blobs""")
7778

7879
self.protocol = b"dj0\0" # when using new blob features
79-
80+
8081
def squeeze(self, array, convert_to_scalar=True):
8182
"""
8283
Simplify the input array - squeeze out all singleton dimensions.
@@ -308,7 +309,7 @@ def read_string(self):
308309
def pack_string(s):
309310
blob = s.encode()
310311
return b"\5" + len_u64(blob) + blob
311-
312+
312313
def read_bytes(self):
313314
return self.read_binary(self.read_value())
314315

@@ -346,7 +347,7 @@ def pack_set(self, t):
346347

347348
def read_dict(self):
348349
return OrderedDict((self.read_blob(self.read_value()), self.read_blob(self.read_value()))
349-
for _ in range(self.read_value()))
350+
for _ in range(self.read_value()))
350351

351352
def pack_dict(self, d):
352353
return b"\4" + len_u64(d) + b"".join(
@@ -428,7 +429,7 @@ def read_zero_terminated_string(self):
428429
data = self._blob[self._pos:target].decode()
429430
self._pos = target + 1
430431
return data
431-
432+
432433
def read_value(self, dtype='uint64', count=1):
433434
data = np.frombuffer(self._blob, dtype=dtype, count=count, offset=self._pos)
434435
self._pos += data.dtype.itemsize * data.size

0 commit comments

Comments
 (0)