Skip to content

Commit

Permalink
Merge pull request #112 from nlesc-nano/devel
Browse files Browse the repository at this point in the history
CAT 0.8.6
  • Loading branch information
BvB93 authored May 12, 2020
2 parents e4d9f2f + f5e57ac commit fc243e1
Show file tree
Hide file tree
Showing 13 changed files with 240 additions and 56 deletions.
5 changes: 4 additions & 1 deletion CAT/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@
read_mol, set_mol_prop
)

from .utils import get_template
from .utils import get_template, VersionInfo

__version__ = __version__
__author__ = "Bas van Beek"
__email__ = '[email protected]'

version_info = VersionInfo.from_str(__version__)
del VersionInfo

__all__ = [
'job_single_point', 'job_geometry_opt', 'job_freq',

Expand Down
2 changes: 1 addition & 1 deletion CAT/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.8.5'
__version__ = '0.8.6'
135 changes: 135 additions & 0 deletions CAT/_setattr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
"""A module for containing the :class:`SetAttr` class."""

import reprlib
from threading import RLock
from typing import Generic, TypeVar, NoReturn, Dict, Any, Optional

__all__ = ['SetAttr']

T1 = TypeVar('T1')
T2 = TypeVar('T2')
ST = TypeVar('ST', bound='SetAttr')


class SetAttr(Generic[T1, T2]):
"""A context manager for temporarily changing an attribute's value.
The :class:`SetAttr` context manager is thread-safe, reusable and reentrant.
Wanrings
--------
Note that while :meth:`SetAttr.__enter__` and :meth:`SetAttr.__exit__` are thread-safe,
the same does *not* hold for :meth:`SetAttr.__init__`.
Examples
--------
.. code:: python
>>> from CAT.utils import SetAttr
>>> class Test:
... a = False
>>> print(Test.a)
False
>>> set_attr = SetAttr(Test, 'a', True)
>>> with set_attr:
... print(Test.a)
True
"""

__slots__ = ('__weakref__', '_obj', '_name', '_value', '_value_old', '_lock', '_hash')

@property
def obj(self) -> T1:
"""The to-be modified object."""
return self._obj

@property
def name(self) -> str:
"""The name of the to-be modified attribute."""
return self._name

@property
def value(self) -> T2:
"""The value to-be assigned to the :attr:`name` attribute of :attr:`obj`."""
return self._value

@property
def attr(self) -> T2:
"""Get or set the :attr:`~SetAttr.name` attribute of :attr:`SetAttr.obj`."""
return getattr(self.obj, self.name)

@attr.setter
def attr(self, value: T2) -> None:
with self._lock:
setattr(self.obj, self.name, value)

def __init__(self, obj: T1, name: str, value: T2) -> None:
"""Initialize the :class:`SetAttr` context manager.
Parameters
----------
obj : :data:`~typing.Any`
The to-be modified object.
name : :class:`str`
The name of the to-be modified attribute.
value : :data:`~typing.Any`
The value to-be assigned to the **name** attribute of **obj**.
"""
self._obj = obj
self._name = name
self._value = value

self._value_old = self.attr
self._lock = RLock()

def __repr__(self) -> str:
"""Implement :func:`str(self)<str>` and :func:`repr(self)<repr>`."""
obj = object.__repr__(self.obj)
value = reprlib.repr(self.value)
return f'{self.__class__.__name__}(obj={obj}, name={self.name!r}, value={value})'

def __eq__(self, value: Any) -> bool:
"""Implement :func:`self == value<object.__eq__>`."""
if type(self) is not type(value):
return False
return self.obj is value.obj and self.name == value.name and self.value == value.value

def __reduce__(self) -> NoReturn:
"""Unsupported operation, raise a :exc:`TypeError`."""
raise TypeError(f"can't pickle {self.__class__.__name__} objects")

def __copy__(self: ST) -> ST:
"""Implement :func:`copy.copy(self)<copy.copy>`."""
return self

def __deepcopy__(self: ST, memo: Optional[Dict[int, Any]] = None) -> ST:
"""Implement :func:`copy.deepcopy(self, memo=...)<copy.deepcopy>`."""
return self

def __hash__(self) -> int:
"""Implement :func:`hash(self)<hash>`.
Warnings
--------
A :exc:`TypeError` will still be raised if :attr:`SetAttr.value` is not hashable.
"""
try:
return self._hash
except AttributeError:
args = (type(self), (id(self.obj), self.name, self.value))
self._hash: int = hash(args)
return self._hash

def __enter__(self) -> None:
"""Enter the context manager, modify :attr:`SetAttr.obj`."""
self.attr = self.value

def __exit__(self, exc_type, exc_value, traceback) -> None:
"""Exit the context manager, restore :attr:`SetAttr.obj`."""
self.attr = self._value_old
2 changes: 1 addition & 1 deletion CAT/attachment/dye.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def connect_ligands_to_core(lig_dict, core, user_min_dist):
FrInd_plams = (np.array(FrInd_rdkit)+1).tolist() # plams counts from 1
Fr_atoms = np.array([lig_cp[c].coords for c in FrInd_plams])
OnlyLig = np.array(
[lig_cp[l].coords for l in range(1, len(lig_cp)+1) if l not in FrInd_plams])
[lig_cp[i].coords for i in range(1, len(lig_cp)+1) if i not in FrInd_plams])
min_dist = np.nanmin(cdist(OnlyLig, Fr_atoms))
lig_cp.properties.min_distance = min_dist

Expand Down
8 changes: 4 additions & 4 deletions CAT/attachment/ligand_attach.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,12 @@ def construct_mol_series(qd_df: SettingsDataFrame, core_df: pd.DataFrame,
ligand_df: pd.DataFrame, path: str,
allignment: str = 'sphere', **kwargs: Any) -> pd.Series:
"""Construct a Series of new quantum dots."""
def _get_mol(i, j, k, l):
def _get_mol(i, j, k, m):
ij = i, j
kl = k, l
return ligand_to_qd(core_df.at[ij, MOL], ligand_df.at[kl, MOL], path, allignment=allignment)
km = k, m
return ligand_to_qd(core_df.at[ij, MOL], ligand_df.at[km, MOL], path, allignment=allignment)

mol_list = [_get_mol(i, j, k, l) for i, j, k, l in qd_df.index]
mol_list = [_get_mol(i, j, k, m) for i, j, k, m in qd_df.index]
return pd.Series(mol_list, index=qd_df.index, name=MOL, dtype=object)


Expand Down
4 changes: 2 additions & 2 deletions CAT/attachment/substitution_symmetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,8 @@ def swap_pairs(j):
j[:2], j[2:] = j[2:], j[:2]
return j

def rotate_list(l, n):
return l[n:] + l[:n]
def rotate_list(lst, n):
return lst[n:] + lst[:n]

def swap_two_last(j):
j[-1], j[-2] = j[-2], j[-1]
Expand Down
1 change: 1 addition & 0 deletions CAT/recipes.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
>>> from CAT.recipes import dissociate_surface, row_accumulator
>>> from CAT.recipes import coordination_number
>>> from CAT.recipes import add_ligands, export_dyes
>>> from CAT.recipes import mutli_ligand_job
...
"""
Expand Down
Loading

0 comments on commit fc243e1

Please sign in to comment.