Skip to content

Commit

Permalink
Merge branch 'develop' into python3_restapi
Browse files Browse the repository at this point in the history
  • Loading branch information
Snehal Kumbhar committed Oct 25, 2018
2 parents f2b4020 + 9cceedb commit 85308fb
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 148 deletions.
116 changes: 62 additions & 54 deletions aiida/backends/tests/dbimporters.py
Expand Up @@ -20,7 +20,6 @@

from aiida.backends.testbase import AiidaTestCase

@unittest.skipIf(six.PY3, "Broken on Python 3")
class TestCodDbImporter(AiidaTestCase):
"""
Test the CodDbImporter class.
Expand All @@ -29,6 +28,7 @@ class TestCodDbImporter(AiidaTestCase):

def test_query_construction_1(self):
from aiida.tools.dbimporters.plugins.cod import CodDbImporter
import re

codi = CodDbImporter()
q = codi.query_sql(id=["1000000", 3000000],
Expand All @@ -43,28 +43,34 @@ def test_query_construction_1(self):
measurement_temp=[0, 10.5],
measurement_pressure=[1000, 1001],
determination_method=["single crystal", None])

# Rounding errors occurr in Python 2 and Python 3 thus they are averted using
# the following precision stripping regular expressions.
q = re.sub(r'(\d\.\d{6})\d+', r'\1', q)
q = re.sub(r'(120.00)39+', r'\g<1>4', q)

self.assertEquals(q, \
"SELECT file, svnrevision FROM data WHERE "
"(status IS NULL OR status != 'retracted') AND "
"(method IN ('single crystal') OR method IS NULL) AND "
"(file IN (1000000, 3000000)) AND "
"(a BETWEEN 3.332333 AND 3.334333 OR "
"a BETWEEN 0.999 AND 1.001) AND "
"(alpha BETWEEN 1.665666 AND 1.667666 OR "
"alpha BETWEEN -0.001 AND 0.001) AND "
"(chemname LIKE '%caffeine%' OR "
"chemname LIKE '%serotonine%') AND "
"(method IN ('single crystal') OR method IS NULL) AND "
"(formula REGEXP ' C[0-9 ]' AND "
"formula REGEXP ' H[0-9 ]' AND "
"formula REGEXP ' Cl[0-9 ]') AND "
"(formula IN ('- C6 H6 -')) AND "
"(a BETWEEN 3.33233333333 AND 3.33433333333 OR "
"a BETWEEN 0.999 AND 1.001) AND "
"(file IN (1000000, 3000000)) AND "
"(cellpressure BETWEEN 999 AND 1001 OR "
"cellpressure BETWEEN 1000 AND 1002) AND "
"(celltemp BETWEEN -0.001 AND 0.001 OR "
"celltemp BETWEEN 10.499 AND 10.501) AND "
"(nel IN (5)) AND (sg IN ('P -1')) AND "
"(vol BETWEEN 99.999 AND 100.001 OR "
"vol BETWEEN 120.004 AND 120.006) AND "
"(alpha BETWEEN 1.66566666667 AND 1.66766666667 OR "
"alpha BETWEEN -0.001 AND 0.001) AND "
"(cellpressure BETWEEN 999 AND 1001 OR "
"cellpressure BETWEEN 1000 AND 1002) AND "
"(formula REGEXP ' C[0-9 ]' AND "
"formula REGEXP ' H[0-9 ]' AND "
"formula REGEXP ' Cl[0-9 ]') AND "
"(nel IN (5)) AND (sg IN ('P -1'))")
"vol BETWEEN 120.004 AND 120.006)")

def test_datatype_checks(self):
"""
Expand All @@ -91,7 +97,7 @@ def test_datatype_checks(self):
codi._volume_clause]
results = [[0, 4, 4, 0, 1, 1],
[0, 0, 0, 0, 1, 1],
[2, 0, 2, 0, 2, 2],
[2, 0, 0, 0, 2, 2],
[0, 0, 0, 0, 1, 1],
[2, 0, 0, 0, 2, 2],
[0, 3, 3, 3, 0, 3]]
Expand All @@ -116,14 +122,16 @@ def test_dbentry_creation(self):
{'id': '1000001', 'svnrevision': '1234'},
{'id': '2000000', 'svnrevision': '1234'}])
self.assertEquals(len(results), 3)
self.assertEquals(str(results.at(1)),
'CodEntry(license="CC0",'
'db_name="Crystallography Open Database",version="1234",'
'uri="http://www.crystallography.net/cod/1000001.cif@1234",'
'source_md5=None,db_uri="http://www.crystallography.net",'
'id="1000001",extras={})')
self.assertEquals(results.at(1).source['uri'], \
"http://www.crystallography.net/cod/1000001.cif@1234")
self.assertEquals(results.at(1).source, {
'db_name': 'Crystallography Open Database',
'db_uri': 'http://www.crystallography.net/cod',
'extras': {},
'id': '1000001',
'license': 'CC0',
'source_md5': None,
'uri': 'http://www.crystallography.net/cod/1000001.cif@1234',
'version': '1234',
})
self.assertEquals([x.source['uri'] for x in results],
["http://www.crystallography.net/cod/1000000.cif",
"http://www.crystallography.net/cod/1000001.cif@1234",
Expand All @@ -146,7 +154,7 @@ def test_dbentry_to_cif_node(self):
'070711e8e99108aade31d20cd5c94c48')
self.assertEquals(cif.source, {
'db_name': 'Crystallography Open Database',
'db_uri': 'http://www.crystallography.net',
'db_uri': 'http://www.crystallography.net/cod',
'id': None,
'version': None,
'extras': {},
Expand All @@ -156,7 +164,6 @@ def test_dbentry_to_cif_node(self):
})


@unittest.skipIf(six.PY3, "Broken on Python 3")
class TestTcodDbImporter(AiidaTestCase):
"""
Test the TcodDbImporter class.
Expand All @@ -172,22 +179,22 @@ def test_dbentry_creation(self):
{'id': '10000001', 'svnrevision': '1234'},
{'id': '20000000', 'svnrevision': '1234'}])
self.assertEquals(len(results), 3)
self.assertEquals(str(results.at(1)),
'TcodEntry(license="CC0",'
'db_name="Theoretical Crystallography Open Database",'
'version="1234",'
'uri="http://www.crystallography.net/tcod/10000001.cif@1234",'
'source_md5=None,db_uri="http://www.crystallography.net/tcod",'
'id="10000001",extras={})')
self.assertEquals(results.at(1).source['uri'], \
"http://www.crystallography.net/tcod/10000001.cif@1234")
self.assertEquals(results.at(1).source, {
'db_name': 'Theoretical Crystallography Open Database',
'db_uri': 'http://www.crystallography.net/tcod',
'extras': {},
'id': '10000001',
'license': 'CC0',
'source_md5': None,
'uri': 'http://www.crystallography.net/tcod/10000001.cif@1234',
'version': '1234',
})
self.assertEquals([x.source['uri'] for x in results],
["http://www.crystallography.net/tcod/10000000.cif",
"http://www.crystallography.net/tcod/10000001.cif@1234",
"http://www.crystallography.net/tcod/20000000.cif@1234"])


@unittest.skipIf(six.PY3, "Broken on Python 3")
class TestPcodDbImporter(AiidaTestCase):
"""
Test the PcodDbImporter class.
Expand All @@ -201,18 +208,18 @@ def test_dbentry_creation(self):

results = PcodSearchResults([{'id': '12345678'}])
self.assertEquals(len(results), 1)
self.assertEquals(str(results.at(0)),
'PcodEntry(license="CC0",'
'db_name="Predicted Crystallography Open Database",'
'version=None,'
'uri="http://www.crystallography.net/pcod/cif/1/123/12345678.cif",'
'source_md5=None,db_uri="http://www.crystallography.net/pcod",'
'id="12345678",extras={})')
self.assertEquals([x.source['uri'] for x in results],
["http://www.crystallography.net/pcod/cif/1/123/12345678.cif"])
self.assertEquals(results.at(0).source, {
'db_name': 'Predicted Crystallography Open Database',
'db_uri': 'http://www.crystallography.net/pcod',
'extras': {},
'id': '12345678',
'license': 'CC0',
'source_md5': None,
'uri': 'http://www.crystallography.net/pcod/cif/1/123/12345678.cif',
'version': None,
})


@unittest.skipIf(six.PY3, "Broken on Python 3")
class TestMpodDbImporter(AiidaTestCase):
"""
Test the MpodDbImporter class.
Expand All @@ -226,15 +233,16 @@ def test_dbentry_creation(self):

results = MpodSearchResults([{'id': '1234567'}])
self.assertEquals(len(results), 1)
self.assertEquals(str(results.at(0)),
'MpodEntry(license=None,'
'db_name="Material Properties Open Database",'
'version=None,'
'uri="http://mpod.cimav.edu.mx/datafiles/1234567.mpod",'
'source_md5=None,db_uri="http://mpod.cimav.edu.mx",'
'id="1234567",extras={})')
self.assertEquals([x.source['uri'] for x in results],
["http://mpod.cimav.edu.mx/datafiles/1234567.mpod"])
self.assertEquals(results.at(0).source, {
'db_name': 'Material Properties Open Database',
'db_uri': 'http://mpod.cimav.edu.mx',
'extras': {},
'id': '1234567',
'license': None,
'source_md5': None,
'uri': 'http://mpod.cimav.edu.mx/datafiles/1234567.mpod',
'version': None,
})


class TestNnincDbImporter(AiidaTestCase):
Expand Down
59 changes: 33 additions & 26 deletions aiida/backends/tests/tcodexporter.py
Expand Up @@ -74,6 +74,11 @@ def test_contents_encoding_1(self):
(b'line\n=3Bline', 'quoted-printable'))
self.assertEquals(cif_encode_contents(b'tabbed\ttext'),
(b'tabbed=09text', 'quoted-printable'))

# Angstrom symbol 'Å' will be encoded as two bytes, thus encoding it
# for CIF will produce two quoted-printable entities, '=C3' and '=85',
# one for each byte.

self.assertEquals(cif_encode_contents(u'angstrom Å'.encode('utf-8')),
(b'angstrom =C3=85', 'quoted-printable'))
self.assertEquals(cif_encode_contents(b'.'),
Expand Down Expand Up @@ -150,8 +155,6 @@ def test_collect_files(self):
@unittest.skipIf(not has_ase(), "Unable to import ase")
@unittest.skipIf(not has_spglib(), "Unable to import spglib")
@unittest.skipIf(not has_pycifrw(), "Unable to import PyCifRW")
@unittest.skipIf(not has_nwchem_plugin(), "NWChem plugin is not installed")
@unittest.skipIf(six.PY3, "Broken on Python 3")
def test_cif_structure_roundtrip(self):
from aiida.tools.dbexporters.tcod import export_cif, export_values
from aiida.orm import Code
Expand Down Expand Up @@ -329,8 +332,6 @@ def test_nwcpymatgen_translation(self):
@unittest.skipIf(not has_ase(), "Unable to import ase")
@unittest.skipIf(not has_spglib(), "Unable to import spglib")
@unittest.skipIf(not has_pycifrw(), "Unable to import PyCifRW")
@unittest.skipIf(not has_nwchem_plugin(), "NWChem plugin is not installed")
@unittest.skipIf(six.PY3, "Broken on Python 3")
def test_inline_export(self):
from aiida.orm.data.cif import CifData
from aiida.tools.dbexporters.tcod import export_values
Expand Down Expand Up @@ -387,7 +388,7 @@ def test_symmetry_reduction(self):
self.assertEqual(val['_symmetry_space_group_name_H-M'], 'Pm-3m')
self.assertEqual(val['_symmetry_space_group_name_Hall'], '-P 4 2 3')

@unittest.skipIf(six.PY3, "Broken on Python 3")

def test_cmdline_parameters(self):
"""
Ensuring that neither extend_with_cmdline_parameters() nor
Expand Down Expand Up @@ -569,28 +570,34 @@ def check_gzip_base64(self, text):
self.assertEquals(text, decoded)
self.assertEquals(text, decoded_universal)

check_ncr(self, '.', '&#46;')
check_ncr(self, '?', '&#63;')
check_ncr(self, ';\n', '&#59;\n')
check_ncr(self, 'line\n;line', 'line\n&#59;line')
check_ncr(self, 'tabbed\ttext', 'tabbed&#9;text')
check_ncr(self, 'angstrom Å', 'angstrom &#195;&#133;')
check_ncr(self, '<html>&#195;&#133;</html>',
'<html>&#38;#195;&#38;#133;</html>')

check_quoted_printable(self, '.', '=2E')
check_quoted_printable(self, '?', '=3F')
check_quoted_printable(self, ';\n', '=3B\n')
check_quoted_printable(self, 'line\n;line', 'line\n=3Bline')
check_quoted_printable(self, 'tabbed\ttext', 'tabbed=09text')
check_quoted_printable(self, 'angstrom Å', 'angstrom =C3=85')
check_quoted_printable(self, 'line\rline\x00', 'line=0Dline=00')
check_ncr(self, b'.', b'&#46;')
check_ncr(self, b'?', b'&#63;')
check_ncr(self, b';\n', b'&#59;\n')
check_ncr(self, b'line\n;line', b'line\n&#59;line')
check_ncr(self, b'tabbed\ttext', b'tabbed&#9;text')
# Angstrom symbol 'Å' will be encoded as two bytes, thus encoding it
# for CIF will produce two NCR entities, '&#195;' and '&#133;', one for
# each byte.
check_ncr(self, u'angstrom Å'.encode('utf-8'), b'angstrom &#195;&#133;')
check_ncr(self, b'<html>&#195;&#133;</html>',
b'<html>&#38;#195;&#38;#133;</html>')

check_quoted_printable(self, b'.', b'=2E')
check_quoted_printable(self, b'?', b'=3F')
check_quoted_printable(self, b';\n', b'=3B\n')
check_quoted_printable(self, b'line\n;line', b'line\n=3Bline')
check_quoted_printable(self, b'tabbed\ttext', b'tabbed=09text')
# Angstrom symbol 'Å' will be encoded as two bytes, thus encoding it
# for CIF will produce two quoted-printable entities, '=C3' and '=85',
# one for each byte.
check_quoted_printable(self, u'angstrom Å'.encode('utf-8'), b'angstrom =C3=85')
check_quoted_printable(self, b'line\rline\x00', b'line=0Dline=00')
# This one is particularly tricky: a long line is folded by the QP
# and the semicolon sign becomes the first character on a new line.
check_quoted_printable(self,
"Å{};a".format("".join("a" for i in range(0, 69))),
'=C3=85aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaa=\n=3Ba')
u"Å{};a".format("".join("a" for i in range(0, 69))).encode('utf-8'),
b'=C3=85aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
b'aaaaaaaaaaaaaaaaaaaaaaaaaaaaa=\n=3Ba')

check_base64(self, 'angstrom ÅÅÅ', 'YW5nc3Ryb20gw4XDhcOF')
check_gzip_base64(self, 'angstrom ÅÅÅ')
check_base64(self, u'angstrom ÅÅÅ'.encode('utf-8'), b'YW5nc3Ryb20gw4XDhcOF')
check_gzip_base64(self, u'angstrom ÅÅÅ'.encode('utf-8'))
2 changes: 1 addition & 1 deletion aiida/cmdline/utils/shell.py
Expand Up @@ -127,7 +127,7 @@ def _ipython_pre_100():

def _ipython():
"""Start IPython >= 1.0"""
from IPython import start_ipython # pylint: disable=import-error
from IPython import start_ipython # pylint: disable=import-error,no-name-in-module

user_ns = get_start_namespace()
if user_ns:
Expand Down
23 changes: 14 additions & 9 deletions aiida/orm/data/cif.py
Expand Up @@ -270,7 +270,7 @@ def pycifrw_from_cif(datablocks, loops=None, names=None):
Constructs PyCifRW's CifFile from an array of CIF datablocks.
:param datablocks: an array of CIF datablocks
:param loops: optional list of lists of CIF tag loops.
:param loops: optional dict of lists of CIF tag loops.
:param names: optional list of datablock names
:return: CifFile
"""
Expand Down Expand Up @@ -300,9 +300,10 @@ def pycifrw_from_cif(datablocks, loops=None, names=None):
name = names[i]
datablock = CifBlock()
cif[name] = datablock
tags_in_loops = []
for loopname in loops.keys():
loopdata = ([[]], [[]])
row_size = None
tags_seen = []
for tag in loops[loopname]:
if tag in values:
tag_values = values.pop(tag)
Expand All @@ -315,15 +316,19 @@ def pycifrw_from_cif(datablocks, loops=None, names=None):
"'{}' is different from "
"the others in the same "
"loop".format(tag))
loopdata[0][0].append(tag)
loopdata[1][0].append(tag_values)
if row_size == 0:
continue
datablock.AddItem(tag, tag_values)
tags_seen.append(tag)
tags_in_loops.append(tag)
if row_size is not None and row_size > 0:
datablock.AddCifItem(loopdata)
datablock.CreateLoop(datanames=tags_seen)
for tag in sorted(values.keys()):
datablock[tag] = values[tag]
# create automatically a loop for non-scalar values
if isinstance(values[tag], (tuple, list)) and tag not in loops.keys():
datablock.CreateLoop([tag])
if not tag in tags_in_loops:
datablock.AddItem(tag, values[tag])
# create automatically a loop for non-scalar values
if isinstance(values[tag], (tuple, list)) and tag not in loops.keys():
datablock.CreateLoop([tag])
return cif


Expand Down

0 comments on commit 85308fb

Please sign in to comment.