Skip to content

Commit 120e9ac

Browse files
authored
Merge pull request #2261 from antgonza/upgrading-software
upgrading software
2 parents 2e102b4 + de5c89f commit 120e9ac

File tree

10 files changed

+158
-160
lines changed

10 files changed

+158
-160
lines changed

qiita_db/metadata_template/util.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import pandas as pd
1515
import numpy as np
1616
import warnings
17-
from skbio.io.util import open_file
1817
from skbio.util import find_duplicates
1918

2019
import qiita_db as qdb
@@ -102,7 +101,7 @@ def load_template_to_dataframe(fn, index='sample_name'):
102101
"""
103102
# Load in file lines
104103
holdfile = None
105-
with open_file(fn, mode='U') as f:
104+
with qdb.util.open_file(fn, mode='U') as f:
106105
errors = defaultdict(list)
107106
holdfile = f.readlines()
108107
# here we are checking for non UTF-8 chars
@@ -333,7 +332,7 @@ def looks_like_qiime_mapping_file(fp):
333332
some other different column.
334333
"""
335334
first_line = None
336-
with open_file(fp, mode='U') as f:
335+
with qdb.util.open_file(fp, mode='U') as f:
337336
first_line = f.readline()
338337
if not first_line:
339338
return False

qiita_db/search.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969

7070
import pandas as pd
7171
from future.utils import viewitems
72+
from future.builtins import str
7273

7374
from qiita_core.qiita_settings import qiita_config
7475
import qiita_db as qdb

qiita_db/test/test_util.py

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
# -----------------------------------------------------------------------------
88

99
from unittest import TestCase, main
10-
from tempfile import mkstemp
10+
from tempfile import mkstemp, NamedTemporaryFile, TemporaryFile
1111
from os import close, remove, makedirs, mkdir
1212
from os.path import join, exists, basename
1313
from shutil import rmtree
1414
from datetime import datetime
1515
from functools import partial
1616
from string import punctuation
17-
17+
import h5py
18+
from six import StringIO, BytesIO
1819
import pandas as pd
1920

2021
from qiita_core.util import qiita_test_checker
@@ -869,5 +870,77 @@ def test_get_artifacts_information(self):
869870
self.assertItemsEqual(obs, exp)
870871

871872

873+
class TestFilePathOpening(TestCase):
874+
"""Tests adapted from scikit-bio's skbio.io.util tests"""
875+
def test_is_string_or_bytes(self):
876+
self.assertTrue(qdb.util._is_string_or_bytes('foo'))
877+
self.assertTrue(qdb.util._is_string_or_bytes(u'foo'))
878+
self.assertTrue(qdb.util._is_string_or_bytes(b'foo'))
879+
self.assertFalse(qdb.util._is_string_or_bytes(StringIO('bar')))
880+
self.assertFalse(qdb.util._is_string_or_bytes([1]))
881+
882+
def test_file_closed(self):
883+
"""File gets closed in decorator"""
884+
f = NamedTemporaryFile('r')
885+
filepath = f.name
886+
with qdb.util.open_file(filepath) as fh:
887+
pass
888+
self.assertTrue(fh.closed)
889+
890+
def test_file_closed_harder(self):
891+
"""File gets closed in decorator, even if exceptions happen."""
892+
f = NamedTemporaryFile('r')
893+
filepath = f.name
894+
try:
895+
with qdb.util.open_file(filepath) as fh:
896+
raise TypeError
897+
except TypeError:
898+
self.assertTrue(fh.closed)
899+
else:
900+
# If we're here, no exceptions have been raised inside the
901+
# try clause, so the context manager swallowed them. No
902+
# good.
903+
raise Exception("`open_file` didn't propagate exceptions")
904+
905+
def test_filehandle(self):
906+
"""Filehandles slip through untouched"""
907+
with TemporaryFile('r') as fh:
908+
with qdb.util.open_file(fh) as ffh:
909+
self.assertTrue(fh is ffh)
910+
# And it doesn't close the file-handle
911+
self.assertFalse(fh.closed)
912+
913+
def test_StringIO(self):
914+
"""StringIO (useful e.g. for testing) slips through."""
915+
f = StringIO("File contents")
916+
with qdb.util.open_file(f) as fh:
917+
self.assertTrue(fh is f)
918+
919+
def test_BytesIO(self):
920+
"""BytesIO (useful e.g. for testing) slips through."""
921+
f = BytesIO(b"File contents")
922+
with qdb.util.open_file(f) as fh:
923+
self.assertTrue(fh is f)
924+
925+
def test_hdf5IO(self):
926+
f = h5py.File('test', driver='core', backing_store=False)
927+
with qdb.util.open_file(f) as fh:
928+
self.assertTrue(fh is f)
929+
930+
def test_hdf5IO_open(self):
931+
name = None
932+
with NamedTemporaryFile(delete=False) as fh:
933+
name = fh.name
934+
fh.close()
935+
936+
h5file = h5py.File(name, 'w')
937+
h5file.close()
938+
939+
with qdb.util.open_file(name) as fh_inner:
940+
self.assertTrue(isinstance(fh_inner, h5py.File))
941+
942+
remove(name)
943+
944+
872945
if __name__ == '__main__':
873946
main()

qiita_db/util.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
from json import dumps
5555
from datetime import datetime
5656
from itertools import chain
57+
from contextlib import contextmanager
58+
from future.builtins import bytes, str
59+
import h5py
5760

5861
from qiita_core.exceptions import IncompetentQiitaDeveloperError
5962
import qiita_db as qdb
@@ -1481,3 +1484,67 @@ def get_artifacts_information(artifact_ids, only_biom=True):
14811484
'files': filepaths})
14821485

14831486
return results
1487+
1488+
1489+
def _is_string_or_bytes(s):
1490+
"""Returns True if input argument is string (unicode or not) or bytes.
1491+
"""
1492+
return isinstance(s, str) or isinstance(s, bytes)
1493+
1494+
1495+
def _get_filehandle(filepath_or, *args, **kwargs):
1496+
"""Open file if `filepath_or` looks like a string/unicode/bytes, else
1497+
pass through.
1498+
"""
1499+
if _is_string_or_bytes(filepath_or):
1500+
if h5py.is_hdf5(filepath_or):
1501+
fh, own_fh = h5py.File(filepath_or, *args, **kwargs), True
1502+
else:
1503+
fh, own_fh = open(filepath_or, *args, **kwargs), True
1504+
else:
1505+
fh, own_fh = filepath_or, False
1506+
return fh, own_fh
1507+
1508+
1509+
@contextmanager
1510+
def open_file(filepath_or, *args, **kwargs):
1511+
"""Context manager, like ``open``, but lets file handles and file like
1512+
objects pass untouched.
1513+
1514+
It is useful when implementing a function that can accept both
1515+
strings and file-like objects (like numpy.loadtxt, etc).
1516+
1517+
This method differs slightly from scikit-bio's implementation in that it
1518+
handles HDF5 files appropriately.
1519+
1520+
Parameters
1521+
----------
1522+
filepath_or : str/bytes/unicode string or file-like
1523+
If string, file to be opened using ``h5py.File`` if the file is an
1524+
HDF5 file, otherwise builtin ``open`` will be used. If it is not a
1525+
string, the object is just returned untouched.
1526+
1527+
Other parameters
1528+
----------------
1529+
args, kwargs : tuple, dict
1530+
When `filepath_or` is a string, any extra arguments are passed
1531+
on to the ``open`` builtin.
1532+
1533+
Examples
1534+
--------
1535+
>>> with open_file('filename') as f: # doctest: +SKIP
1536+
... pass
1537+
>>> fh = open('filename') # doctest: +SKIP
1538+
>>> with open_file(fh) as f: # doctest: +SKIP
1539+
... pass
1540+
>>> fh.closed # doctest: +SKIP
1541+
False
1542+
>>> fh.close() # doctest: +SKIP
1543+
1544+
"""
1545+
fh, own_fh = _get_filehandle(filepath_or, *args, **kwargs)
1546+
try:
1547+
yield fh
1548+
finally:
1549+
if own_fh:
1550+
fh.close()

qiita_pet/handlers/api_proxy/artifact.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
from json import dumps
1111

1212
from future.utils import viewitems
13+
from itertools import chain
1314
from moi import r_client
14-
from skbio.util import flatten
1515

1616
from qiita_core.util import execute_as_transaction
1717
from qiita_core.qiita_settings import qiita_config
@@ -103,8 +103,8 @@ def artifact_get_prep_req(user_id, artifact_ids):
103103
if access_error:
104104
return access_error
105105

106-
samples[aid] = flatten(
107-
[pt.keys() for pt in Artifact(aid).prep_templates])
106+
samples[aid] = list(chain(
107+
*[pt.keys() for pt in Artifact(aid).prep_templates]))
108108

109109
return {'status': 'success', 'msg': '', 'data': samples}
110110

@@ -183,6 +183,7 @@ def artifact_post_req(user_id, filepaths, artifact_type, name,
183183
uploads_path = get_mountpoint('uploads')[0][1]
184184
path_builder = partial(join, uploads_path, str(study_id))
185185
cleaned_filepaths = {}
186+
186187
for ftype, file_list in viewitems(filepaths):
187188
# JavaScript sends us this list as a comma-separated list
188189
for fp in file_list.split(','):

qiita_ware/ebi.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@
2222

2323
from qiita_core.qiita_settings import qiita_config
2424
from qiita_ware.exceptions import EBISubmissionError
25-
from qiita_ware.util import open_file
2625
from qiita_db.logger import LogEntry
2726
from qiita_db.ontology import Ontology
28-
from qiita_db.util import convert_to_id, get_mountpoint
27+
from qiita_db.util import convert_to_id, get_mountpoint, open_file
2928
from qiita_db.artifact import Artifact
3029

3130

qiita_ware/test/test_util.py

Lines changed: 1 addition & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,11 @@
1010
# The full license is in the file LICENSE, distributed with this software.
1111
# -----------------------------------------------------------------------------
1212

13-
import os
1413
from unittest import TestCase, main
15-
import tempfile
16-
17-
import h5py
1814
import numpy as np
19-
from six import StringIO, BytesIO
2015

2116
from qiita_db.metadata_template.prep_template import PrepTemplate
22-
from qiita_ware.util import (per_sample_sequences, open_file,
23-
_is_string_or_bytes)
17+
from qiita_ware.util import per_sample_sequences
2418

2519

2620
def mock_sequence_iter(items):
@@ -111,78 +105,6 @@ def test_dataframe_from_template(self):
111105
u'study_center'})
112106

113107

114-
class TestFilePathOpening(TestCase):
115-
"""Tests adapted from scikit-bio's skbio.io.util tests"""
116-
def test_is_string_or_bytes(self):
117-
self.assertTrue(_is_string_or_bytes('foo'))
118-
self.assertTrue(_is_string_or_bytes(u'foo'))
119-
self.assertTrue(_is_string_or_bytes(b'foo'))
120-
self.assertFalse(_is_string_or_bytes(StringIO('bar')))
121-
self.assertFalse(_is_string_or_bytes([1]))
122-
123-
def test_file_closed(self):
124-
"""File gets closed in decorator"""
125-
f = tempfile.NamedTemporaryFile('r')
126-
filepath = f.name
127-
with open_file(filepath) as fh:
128-
pass
129-
self.assertTrue(fh.closed)
130-
131-
def test_file_closed_harder(self):
132-
"""File gets closed in decorator, even if exceptions happen."""
133-
f = tempfile.NamedTemporaryFile('r')
134-
filepath = f.name
135-
try:
136-
with open_file(filepath) as fh:
137-
raise TypeError
138-
except TypeError:
139-
self.assertTrue(fh.closed)
140-
else:
141-
# If we're here, no exceptions have been raised inside the
142-
# try clause, so the context manager swallowed them. No
143-
# good.
144-
raise Exception("`open_file` didn't propagate exceptions")
145-
146-
def test_filehandle(self):
147-
"""Filehandles slip through untouched"""
148-
with tempfile.TemporaryFile('r') as fh:
149-
with open_file(fh) as ffh:
150-
self.assertTrue(fh is ffh)
151-
# And it doesn't close the file-handle
152-
self.assertFalse(fh.closed)
153-
154-
def test_StringIO(self):
155-
"""StringIO (useful e.g. for testing) slips through."""
156-
f = StringIO("File contents")
157-
with open_file(f) as fh:
158-
self.assertTrue(fh is f)
159-
160-
def test_BytesIO(self):
161-
"""BytesIO (useful e.g. for testing) slips through."""
162-
f = BytesIO(b"File contents")
163-
with open_file(f) as fh:
164-
self.assertTrue(fh is f)
165-
166-
def test_hdf5IO(self):
167-
f = h5py.File('test', driver='core', backing_store=False)
168-
with open_file(f) as fh:
169-
self.assertTrue(fh is f)
170-
171-
def test_hdf5IO_open(self):
172-
name = None
173-
with tempfile.NamedTemporaryFile(delete=False) as fh:
174-
name = fh.name
175-
fh.close()
176-
177-
h5file = h5py.File(name, 'w')
178-
h5file.close()
179-
180-
with open_file(name) as fh_inner:
181-
self.assertTrue(isinstance(fh_inner, h5py.File))
182-
183-
os.remove(name)
184-
185-
186108
# comment indicates the expected random value
187109
sequences = [
188110
('a_1', 'AATTGGCC-a1'), # 2, 3624216819017203053

0 commit comments

Comments
 (0)