"""Retrieval of test resources."""
from contextlib import contextmanager
import shutil
import tempfile
import importlib_resources
from aiida_gulp.tests import raw_files as resource_module
try:
import pathlib
except ImportError:
import pathlib2 as pathlib # noqa: F401
# __package__ returns None in python 2.7
RESOURCE_MODULE = resource_module.__package__ or "aiida_gulp.tests.raw_files"
[docs]@contextmanager
def resource_context(*path, **kwargs):
"""Provide a context manager that yields a pathlib.Path object to a resource file or directory.
If the resource does not already exist on its own on the file system,
a temporary directory/file will be created. If the directory/file was created, it
will be deleted upon exiting the context manager (no exception is
raised if the directory was deleted prior to the context manager
exiting).
"""
if len(path) == 0:
raise TypeError("must provide a path")
final_name = path[-1]
package = ".".join([RESOURCE_MODULE] + list(path[:-1]))
ignore = kwargs.pop("ignore", (".DS_Store", "__init__.py"))
if importlib_resources.is_resource(package, final_name):
# the resource is a file
with importlib_resources.path(package, final_name) as path:
yield path.absolute()
else:
# the resource is a directory
package = package + "." + final_name
# TODO if the package folder exists on the file system it would be ideal to just return that
# but importlib_resources doesn't provide a public API for that
resources = [
c
for c in importlib_resources.contents(package)
if importlib_resources.is_resource(package, c) and c not in ignore
]
folder_path = pathlib.Path(tempfile.mkdtemp())
try:
for resource in resources:
with (folder_path / resource).open("wb") as handle:
handle.write(importlib_resources.read_binary(package, resource))
yield folder_path
finally:
if folder_path.exists():
shutil.rmtree(str(folder_path))
[docs]def read_resource_text(*path, **kwargs): # Note: can't use encoding=None in python 2.7
"""Return the decoded string of the resource.
The decoding-related arguments have the same semantics as those of
bytes.decode().
"""
if len(path) == 0:
raise TypeError("must provide a path")
file_name = path[-1]
package = ".".join([RESOURCE_MODULE] + list(path[:-1]))
encoding = kwargs.pop("encoding", "utf-8")
return importlib_resources.read_text(package, file_name, encoding)
[docs]def read_resource_binary(*path):
"""Return the binary contents of the resource."""
if len(path) == 0:
raise TypeError("must provide a path")
file_name = path[-1]
package = ".".join([RESOURCE_MODULE] + list(path[:-1]))
return importlib_resources.read_binary(package, file_name)
[docs]def open_resource_text(*path, **kwargs): # Note: can't use encoding=None in python 2.7
"""Return a file-like object opened for text reading of the resource.
If the resource does not already exist on its own on the file system,
a temporary file will be created. If the file was created, it
will be deleted upon exiting the context manager (no exception is
raised if the directory was deleted prior to the context manager
exiting).
"""
if len(path) == 0:
raise TypeError("must provide a path")
file_name = path[-1]
package = ".".join([RESOURCE_MODULE] + list(path[:-1]))
encoding = kwargs.pop("encoding", "utf-8")
return importlib_resources.open_text(package, file_name, encoding)
[docs]def open_resource_binary(*path):
"""Return a file-like object opened for binary reading of the resource.
If the resource does not already exist on its own on the file system,
a temporary file will be created. If the file was created, it
will be deleted upon exiting the context manager (no exception is
raised if the directory was deleted prior to the context manager
exiting).
"""
if len(path) == 0:
raise TypeError("must provide a path")
file_name = path[-1]
package = ".".join([RESOURCE_MODULE] + list(path[:-1]))
return importlib_resources.open_binary(package, file_name)
[docs]def get_test_structure(name):
"""Return an aiida.StructureData for testing."""
from aiida.plugins import DataFactory
from ase.spacegroup import crystal
from aiida_gulp.symmetry import convert_structure
structure_data_cls = DataFactory("structure")
if name == "MgO":
atoms = crystal(
symbols=[12, 8],
basis=[[0, 0, 0], [0.5, 0.5, 0.5]],
spacegroup=225,
cellpar=[4.21, 4.21, 4.21, 90, 90, 90],
)
return structure_data_cls(ase=atoms)
elif name == "NiO_afm":
atoms = crystal(
symbols=[28, 8],
basis=[[0, 0, 0], [0.5, 0.5, 0.5]],
spacegroup=225,
cellpar=[4.164, 4.164, 4.164, 90, 90, 90],
)
atoms.set_tags([1, 1, 2, 2, 0, 0, 0, 0])
return structure_data_cls(ase=atoms)
elif name == "pyrite":
structure_data = {
"lattice": [
[5.38, 0.000000, 0.000000],
[0.000000, 5.38, 0.000000],
[0.000000, 0.000000, 5.38],
],
"fcoords": [
[0.0, 0.0, 0.0],
[0.5, 0.0, 0.5],
[0.0, 0.5, 0.5],
[0.5, 0.5, 0.0],
[0.338, 0.338, 0.338],
[0.662, 0.662, 0.662],
[0.162, 0.662, 0.838],
[0.838, 0.338, 0.162],
[0.662, 0.838, 0.162],
[0.338, 0.162, 0.838],
[0.838, 0.162, 0.662],
[0.162, 0.838, 0.338],
],
"symbols": ["Fe"] * 4 + ["S"] * 8,
"pbc": [True, True, True],
}
return convert_structure(structure_data, "aiida")
elif name == "marcasite":
structure_data = {
"lattice": [
[3.37, 0.000000, 0.000000],
[0.000000, 4.44, 0.000000],
[0.000000, 0.000000, 5.39],
],
"ccoords": [
[0.0, 0.0, 0.0],
[1.685000, 2.220000, 2.695000],
[0.000000, 0.901320, 2.021250],
[0.000000, 3.538680, 3.368750],
[1.685000, 1.318680, 4.716250],
[1.685000, 3.121320, 0.673750],
],
"symbols": ["Fe"] * 2 + ["S"] * 4,
"pbc": [True, True, True],
}
return convert_structure(structure_data, "aiida")
elif name == "zincblende":
structure_data = {
"pbc": [True, True, True],
"atomic_numbers": [26, 26, 26, 26, 16, 16, 16, 16],
"ccoords": [
[0.0, 0.0, 0.0],
[2.71, 2.71, 0.0],
[0.0, 2.71, 2.71],
[2.71, 0.0, 2.71],
[1.355, 1.355, 1.355],
[4.065, 4.065, 1.355],
[1.355, 4.065, 4.065],
[4.065, 1.355, 4.065],
],
"lattice": [[5.42, 0.0, 0.0], [0.0, 5.42, 0.0], [0.0, 0.0, 5.42]],
"equivalent": [0, 0, 0, 0, 0, 0, 0, 0],
}
return convert_structure(structure_data, "aiida")
elif name == "s2_molecule":
structure_data = {
"pbc": [True, False, False],
"atomic_numbers": [16, 16],
"ccoords": [[0.0, 0.0, 0.0], [1.89, 0.0, 0.0]],
"lattice": [[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]],
"equivalent": [0, 0],
}
return convert_structure(structure_data, "aiida")
raise ValueError(name)