Skip to content

Commit e6b46a6

Browse files
Merge branch 'v3.4.0' into deprecate-assignUniqueLabels
2 parents 2a1f30e + ca9116a commit e6b46a6

File tree

10 files changed

+129
-9
lines changed

10 files changed

+129
-9
lines changed

news/deprecate-addNewItem.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
**Added:**
2+
3+
* Added `diffpy.structure.Structure.add_new_atom` in replace of `addNewAtom`
4+
5+
**Changed:**
6+
7+
* <news item>
8+
9+
**Deprecated:**
10+
11+
* Deprecated `diffpy.structure.Structure.addNewAtom` method for removal in version 4.0.0
12+
13+
**Removed:**
14+
15+
* <news item>
16+
17+
**Fixed:**
18+
19+
* <news item>
20+
21+
**Security:**
22+
23+
* <news item>

src/diffpy/structure/parsers/p_cif.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ def _parse_atom_site_label(self, block):
497497
if curlabel == "?":
498498
continue
499499
self.labelindex[curlabel] = len(self.stru)
500-
self.stru.addNewAtom()
500+
self.stru.add_new_atom()
501501
a = self.stru.getLastAtom()
502502
for fset, val in zip(prop_setters, values):
503503
fset(a, val)

src/diffpy/structure/parsers/p_discus.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ def _parse_atom(self, words):
264264
element = words[0][0:1].upper() + words[0][1:].lower()
265265
xyz = [float(w) for w in words[1:4]]
266266
Biso = float(words[4])
267-
self.stru.addNewAtom(element, xyz)
267+
self.stru.add_new_atom(element, xyz)
268268
a = self.stru.getLastAtom()
269269
a.Bisoequiv = Biso
270270
return

src/diffpy/structure/parsers/p_pdb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ def parseLines(self, lines):
197197
# get element from the first 2 characters of name
198198
element = line[12:14].strip()
199199
element = element[0].upper() + element[1:].lower()
200-
stru.addNewAtom(element, occupancy=occupancy, label=name)
200+
stru.add_new_atom(element, occupancy=occupancy, label=name)
201201
last_atom = stru.getLastAtom()
202202
last_atom.xyz_cartn = rc
203203
last_atom.Uisoequiv = uiso

src/diffpy/structure/parsers/p_pdffit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def parseLines(self, lines):
132132
element = wl1[0][0].upper() + wl1[0][1:].lower()
133133
xyz = [float(w) for w in wl1[1:4]]
134134
occ = float(wl1[4])
135-
stru.addNewAtom(element, xyz=xyz, occupancy=occ)
135+
stru.add_new_atom(element, xyz=xyz, occupancy=occ)
136136
a = stru.getLastAtom()
137137
p_nl += 1
138138
wl2 = next(ilines).split()

src/diffpy/structure/parsers/p_rawxyz.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def parseLines(self, lines):
103103
xyz = [float(f) for f in fields[x_idx : x_idx + 3]]
104104
if len(xyz) == 2:
105105
xyz.append(0.0)
106-
stru.addNewAtom(element, xyz=xyz)
106+
stru.add_new_atom(element, xyz=xyz)
107107
except ValueError:
108108
emsg = "%d: invalid number" % p_nl
109109
exc_type, exc_value, exc_traceback = sys.exc_info()

src/diffpy/structure/parsers/p_xcfg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def parseLines(self, lines):
269269
elif len(words) == xcfg_entry_count and p_element is not None:
270270
fields = [float(w) for w in words]
271271
xyz = [xcfg_A * xi for xi in fields[:3]]
272-
stru.addNewAtom(p_element, xyz=xyz)
272+
stru.add_new_atom(p_element, xyz=xyz)
273273
a = stru[-1]
274274
_assign_auxiliaries(
275275
a,

src/diffpy/structure/parsers/p_xyz.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def parseLines(self, lines):
109109
element = fields[0]
110110
element = element[0].upper() + element[1:].lower()
111111
xyz = [float(f) for f in fields[1:4]]
112-
stru.addNewAtom(element, xyz=xyz)
112+
stru.add_new_atom(element, xyz=xyz)
113113
except ValueError:
114114
exc_type, exc_value, exc_traceback = sys.exc_info()
115115
emsg = "%d: invalid number format" % p_nl

src/diffpy/structure/structure.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""This module defines class `Structure`."""
1616

1717
import copy as copymod
18+
import warnings
1819

1920
import numpy
2021

@@ -31,6 +32,10 @@
3132
base,
3233
"assignUniqueLabels",
3334
"assign_unique_labels",
35+
addNewAtom_deprecation_msg = build_deprecation_message(
36+
base,
37+
"addNewAtom",
38+
"add_new_atom",
3439
removal_version,
3540
)
3641

@@ -155,17 +160,40 @@ def __str__(self):
155160
s_atoms = "\n".join([str(a) for a in self])
156161
return s_lattice + "\n" + s_atoms
157162

163+
@deprecated(addNewAtom_deprecation_msg)
158164
def addNewAtom(self, *args, **kwargs):
165+
"""This function has been deprecated and will be removed in
166+
version 4.0.0.
167+
168+
Please use diffpy.structure.Structure.add_new_atom instead.
169+
"""
170+
self.add_new_atom(*args, **kwargs)
171+
return
172+
173+
def add_new_atom(self, *args, **kwargs):
159174
"""Add new `Atom` instance to the end of this `Structure`.
160175
161176
Parameters
162177
----------
163178
*args, **kwargs :
164179
See `Atom` class constructor.
180+
181+
Raises
182+
------
183+
UserWarning
184+
If an atom with the same element/type and coordinates already exists.
165185
"""
166186
kwargs["lattice"] = self.lattice
167-
a = Atom(*args, **kwargs)
168-
self.append(a, copy=False)
187+
atom = Atom(*args, **kwargs)
188+
for existing in self:
189+
if existing.element == atom.element and numpy.allclose(existing.xyz, atom.xyz):
190+
warnings.warn(
191+
f"Duplicate atom {atom.element} already exists at {atom.xyz!r}",
192+
category=UserWarning,
193+
stacklevel=2,
194+
)
195+
break
196+
self.append(atom, copy=False)
169197
return
170198

171199
def getLastAtom(self):

tests/test_structure.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,23 @@ def test___copy__(self):
120120
# """check Structure.getLastAtom()"""
121121
# return
122122

123+
def test_addNewAtom(self):
124+
"""Duplicate test for the deprecated addNewAtom method.
125+
126+
Remove this test in version 4.0.0
127+
"""
128+
s_lat = Lattice()
129+
structure = Structure(lattice=s_lat)
130+
131+
length = len(structure)
132+
structure.addNewAtom(atype="C", xyz=[0.1, 0.2, 0.3])
133+
expected = len(structure)
134+
actual = length + 1
135+
assert expected == actual
136+
atom_object = structure[-1]
137+
assert atom_object.element == "C"
138+
assert numpy.allclose(atom_object.xyz, [0.1, 0.2, 0.3])
139+
123140
def test_assignUniqueLabels(self):
124141
"""Check Structure.assignUniqueLabels()"""
125142
self.assertEqual("", "".join([a.label for a in self.stru]))
@@ -609,7 +626,59 @@ def test_pickling(self):
609626

610627
# End of class TestStructure
611628

629+
612630
# ----------------------------------------------------------------------------
631+
@pytest.mark.parametrize(
632+
"existing, atype, xyz, expected_len, expected_element, expected_xyz",
633+
[
634+
# Case 1: valid atom added to an empty structure.
635+
# Expect the atom list length to go from 0 to 1.
636+
# Expect the atom attributes are successfully loaded.
637+
(
638+
None,
639+
"C",
640+
[0.1, 0.2, 0.3],
641+
1,
642+
"C",
643+
[0.1, 0.2, 0.3],
644+
),
645+
# Case 2: valid atom added to existing atom list.
646+
# Expect the atom list length to go from 1 to 2.
647+
# Expect the atom attributes are successfully loaded.
648+
(
649+
[Atom("C", [0, 0, 0])],
650+
"Ni",
651+
[0.8, 1.2, 0.9],
652+
2,
653+
"Ni",
654+
[0.8, 1.2, 0.9],
655+
),
656+
],
657+
)
658+
def test_add_new_atom(existing, atype, xyz, expected_len, expected_element, expected_xyz):
659+
"""Check Structure.add_new_item()"""
660+
structure = Structure(existing, lattice=Lattice())
661+
structure.add_new_atom(atype=atype, xyz=xyz)
662+
actual_length = len(structure)
663+
assert expected_len == actual_length
664+
atom_object = structure[-1]
665+
assert atom_object.element == expected_element
666+
assert numpy.allclose(atom_object.xyz, expected_xyz)
667+
668+
669+
def test_add_new_atom_duplicate():
670+
# Case 3: duplicated atom added to the existing atom list.
671+
# Expect the atom to be added and gives a UserWarning.
672+
structure = Structure(
673+
[Atom("C", [0.1, 0.2, 0.3]), Atom("Ni", [0.8, 1.2, 0.9])],
674+
lattice=Lattice(),
675+
)
676+
with pytest.warns(UserWarning):
677+
structure.add_new_atom(atype="C", xyz=[0.1, 0.2, 0.3])
678+
assert len(structure) == 3
679+
assert structure[-1].element == "C"
680+
assert numpy.allclose(structure[-1].xyz, [0.1, 0.2, 0.3])
681+
613682

614683
if __name__ == "__main__":
615684
unittest.main()

0 commit comments

Comments
 (0)